Codeforces Round #533 (Div. 2)題解 by_Hile

前言:本來在週報上誇下海口說一週補一套Div1,結果發現以前打過的好幾場Div2都沒補完,於是這幾周打算先補了打過的Div2,並且寫完題解。
(感覺以前好菜,div2只能出兩題(雖然現在還是很菜


A.Salem and Sticks (1100)

題意:有n (1n1000)n\ (1\leq n \leq 1000)個長度分別爲ai (1ai100)a_i\ (1\leq a_i\leq 100)的木棒,你可以花費biai|b_i-a_i|使一根木棒的長度從aia_i變爲bib_i,求讓所有木棒滿足bit1|b_i-t|\leq1的最小花費與此時的tt

思路:由於aia_i最大隻有100,暴力枚舉所有可能的tt並記錄最小費用即可,時間複雜度O(100n)O(100n)

代碼

#include<bits/stdc++.h>
using namespace std;
int n,a[1010],ans=0x3f3f3f3f,tt;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int t=1;t<=100;t++)
    {
        int sum=0;
        for(int i=1;i<=n;i++)
            sum+=min(abs(a[i]-t),min(abs(a[i]-t+1),abs(a[i]-t-1)));
        if(ans>sum)
        {
            ans=sum;
            tt=t;
        }
    }
    cout<<tt<<" "<<ans;
}

B.Zuhair and Strings (1200)

題意:求出長度爲n (1n2e5)n\ (1\leq n\leq 2e5)的字符串中,不相交且長度爲k (1kn)k\ (1\leq k\leq n)的只含一種字母的子串個數。

思路:暴力記錄所有符合條件的子串,然後找最大數量,時間複雜度O(n)O(n)

代碼

#include<bits/stdc++.h>
using namespace std;
int n,k,ans,mp[26];
string s;
int main()
{
    cin>>n>>k>>s;
    for(int i=0;i<s.size();i++)
    {
        int cnt=0;
        for(int j=i;j<i+k;j++)
        {
            if(s[i]!=s[j])
            {
                cnt=j-i;
                break;
            }
        }
        if(!cnt)
        {
            mp[s[i]-'a']++;
            cnt=k;
        }
        i+=cnt-1;
    }
    for(int i=0;i<26;i++)
        ans=max(ans,mp[i]);
    cout<<ans;
}

C.Ayoub and Lost Array (1500)

題意:存在一長度爲n (1n2e5)n\ (1\leq n \leq 2e5)的數組,其中每個元素的大小都屬於[l,r] (1lr1e9)[l,r]\ (1\leq l\leq r \leq 1e9),求滿足數組所有元素之和mod  3=0\mod 3=0的方案數(對1e9+71e9+7取模)。

思路線性dp,用dp[i][j]dp[i][j]表示枚舉到數組第ii位時和mod  3=j\mod 3=j的方案數(對1e9+71e9+7取模)。則狀態轉移方程爲
dp[i][(j+k)%3]=dp[i][(j+k)%3]+dp[i1][k]cntjdp[i][(j+k)\%3]=dp[i][(j+k)\%3]+dp[i-1][k]*cnt_j
由於從dp[i1][0:2]dp[i-1][0:2]dp[i][0:2]dp[i][0:2]共有九種轉移方法,上述方程表示從kk轉移到(j+k)%3(j+k)\%3
其中cntjcnt_j爲在[l,r][l,r]mod  3=j\mod 3=j的方案數,爲rj+33lj+23\lfloor \frac{r-j+3}{3} \rfloor -\lfloor \frac{l-j+2}{3} \rfloor。(關鍵結論
代碼

#include<bits/stdc++.h>
#define ll long long
#define MOD 1000000007
using namespace std;
ll n,l,r,ans,dp[200010][3];
int main()
{
    cin>>n>>l>>r;
    dp[0][0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<3;j++)
        {
            ll cnt=(r-j+3)/3-(l-j+2)/3;
            for(int k=0;k<3;k++)
                dp[i][(j+k)%3]=(dp[i][(j+k)%3]+dp[i-1][k]*cnt)%MOD;
        }
    }
    cout<<dp[n][0];
}

D.Kilani and the Game (1900)

題意:給定一個n×mn\times m的只由數字、’#‘和’.‘構成的圖,數字ii代表ii號玩家的初始領地,共有pp名玩家,每回合從11號玩家開始進行a[i]a[i]次擴張,ii號玩家每次擴張可以讓圖中所有ii號點四周的’.'變爲ii,求出當整張圖擴張完畢的時候所有數字的數量。

思路BFS,記錄每回合開始的所有玩家的所有源點,依次往外擴張a[i]a[i]的距離後將停止時的點壓入滾動隊列使其成爲下一輪的源點,然後重複上述過程直至所有隊列都爲空,表示遊戲結束,時間複雜度O(nmp)O(nmp)
Bonus:讀題時想到的另一種算法,先進行pp次BFS預處理出所有每一點到每個玩家最近源點的曼哈頓距離(考慮’#’)並用一個10001000101000*1000*10的三維數組儲存,pp點的編號即爲距離最小的玩家的編號,遍歷整張圖後即可統計出答案。
(口頭AC,算法並未實現,正確性和複雜度未知,但時空複雜度顯然高於原算法
代碼

#include<bits/stdc++.h>
using namespace std;
int n,m,p,a[10];//如題
int ans[10],rod=1;//ans[i]:第i號玩家的格子數,rod:當前進行的遊戲輪數
int xy[4][2]={{1,0},{0,1},{-1,0},{0,-1}};//單位向量,便於bfs
bool vis[1010][1010];//當前點是否可行
string s[1010];//存圖
struct node
{
    int x,y,s;//存座標(x,y)和節點深度s
};
queue<node> qu[10][2];//qu[i][]表示i號玩家每一輪的起始節點,滾動一維
void bfs(int x)//bfs求x號玩家第rod輪的擴張情況
{
    while(!qu[x][rod&1].empty())
    {
        node tmp=qu[x][rod&1].front();
        qu[x][rod&1].pop();
        if(tmp.s>rod*a[x]&&!vis[tmp.x][tmp.y])
        {
            qu[x][(rod+1)&1].push(tmp);
            continue;
        }
        if(vis[tmp.x][tmp.y])continue;
        vis[tmp.x][tmp.y]=true;
        ans[x]++;
        for(int i=0;i<4;i++)
        {
            int tx=tmp.x+xy[i][0],ty=tmp.y+xy[i][1];
            if(!vis[tx][ty]&&s[tx][ty]=='.')
                qu[x][rod&1].push({tx,ty,tmp.s+1});
        }
    }
}
int main()
{
    cin>>n>>m>>p;
    for(int i=1;i<=p;i++)cin>>a[i];
    //存圖,並在所給圖的外圍加一圈'#'
    for(int i=0;i<=m+1;i++)s[0].push_back('#'),vis[0][i]=1;
    for(int i=0;i<=m+1;i++)s[n+1].push_back('#'),vis[n+1][i]=1;
    for(int i=1;i<=n;i++)
    {
        s[i].push_back('#');vis[i][0]=1;
        string tmp;cin>>tmp;s[i]+=tmp;
        s[i].push_back('#');vis[i][m+1]=1;
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(isdigit(s[i][j]))
                qu[s[i][j]-'0'][rod&1].push({i,j,0});
            else if(s[i][j]=='#')
                vis[i][j]=1;
    while(true)
    {
        int flag=0;
        for(int i=1;i<=p;i++)
            bfs(i);
        rod++;
        for(int i=1;i<=p;i++)//若所有隊列都爲空說明無法擴張,遊戲結束退出循環
            for(int j=0;j<2;j++)
                if(!qu[i][j].empty())
                    flag++;
        if(!flag)break;
    }
    for(int i=1;i<=p;i++)
        cout<<ans[i]<<" ";
    return 0;
}

E.Helping Hiasat (2200)

題意:未完待續

思路

代碼


發佈了6 篇原創文章 · 獲贊 3 · 訪問量 53
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章