2024.12.20 Codeforces Round 994 (Div. 2)

比赛链接


Solved: 4/6

Rank: 268

EF 都是神题,跑了


A. MEX Destruction

题意:给一个序列,每次操作可以将一个连续子序列改为它的mex,求最少几次操作可将其变为全0。

注意到对整个序列操作 2 次它就会变成 0。因此答案不超过 2。

如果一开始就是全 0,答案是 0;

如果 0 全都在开头和结尾,答案是 1。

#include<bits/stdc++.h>
using namespace std;
#define all(x) (x).begin(),(x).end()

int solve(){
    int n;
    cin>>n;
    vector<int> a(n);
    for(int& x:a)cin>>x;
    if(*max_element(all(a))==0)return 0;
    int p=-1,q=-1;
    for(int i=0;i<n;++i)if(a[i]>0){p=i;break;}
    for(int i=n-1;i>=0;--i)if(a[i]>0){q=i;break;}
    for(int i=p;i<=q;++i)if(a[i]==0)return 2;
    return 1;
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    int T;
    cin>>T;
    while(T--)cout<<solve()<<'\n';
}

B. pspspsps

题意:给一个仅包含 ps. 三个字符的字符串。求一个排列,满足

  • 若第 \(i\) 个字符为 p,则 \(p[1...i]\)\(1\)\(i\) 的排列;

  • 若第 \(i\) 个字符为 s,则 \(s[i...n]\)\(1\)\(n-i+1\) 的排列。

结论:只有前 \(n-1\) 个都不是 p,或者后 \(n-1\) 个都不是 s 时有解。

#include<bits/stdc++.h>
using namespace std;
#define all(x) (x).begin(),(x).end()

bool solve(){
    int n;
    string a;
    cin>>n>>a;
    bool fl=1;
    for(int i=0;i<n-1;++i){
        if(a[i]=='p')fl=0;
    }
    if(fl)return 1;
    fl=1;
    for(int i=1;i<n;++i){
        if(a[i]=='s')fl=0;
    }
    if(fl)return 1;
    return 0;
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    int T;
    cin>>T;
    while(T--)cout<<(solve()?"YES":"NO")<<'\n';
}

C. MEX Cycle

题意:\(n\) 个人围成一圈,每个人和相邻两个人是好友。另外 \(x\)\(y\) 互为好友。给每个人分配一个数,满足第 \(i\) 个数是 \(i\) 所有好友的数的 mex。

先不考虑 \(x\)\(y\)。当 \(n\) 为奇数时,0101...012 符合题意;当 \(n\) 为偶数时,0101...01 符合题意。

因为是一个环,所以顺序可以随便转。当 \(n\) 为奇数时,只需把 \(x\) 放到 2 的位置,可以验证仍然满足题意;当 \(n\) 为偶数时,考虑 \(x,y\) 原本分的数是否相同。如果不同,则无需变动;如果相同,不妨设都是 0。此时把 \(x\) 变成 2 即可。

#include<bits/stdc++.h>
using namespace std;
#define all(x) (x).begin(),(x).end()

void solve(){
    int n,x,y;
    cin>>n>>x>>y,--x,--y;
    vector<int> a(n);
    if(n&1){
        a[x]=2;
        for(int i=1;i<n;++i)a[(x+i)%n]=i&1;
    }
    else{
        if((x^y)&1){
            for(int i=0;i<n;++i)a[i]=i&1;
        }
        else{
            a[x]=2;
            for(int i=1;i<n;++i)a[(x+i)%n]=i&1;
        }
    }
    for(int x:a)cout<<x<<' ';
    cout<<'\n';
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    int T;
    cin>>T;
    while(T--)solve();
}

D. Shift + Esc

题意:\(n\times m\) 的矩阵,你可以花费 \(k\) 的代价将任意一行整体循环左移一位(可多次操作),然后从 \((1,1)\) 开始以最短路径移动到 \((n,m)\),代价为经过的数的和。求最小代价。\(n,m\leq 200\)

dp,\(f(i,j,t)\) 表示当前移动到 \(i\)\(j\) 列且第 \(i\) 行被循环移位 \(t\) 次的最小代价。转移 \(O(1)\)。总复杂度 \(O(nm^2)\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define all(x) (x).begin(),(x).end()

const int N=205;
int n,m;
ll p,a[N][N],f[N][N],g[N];
void solve(){
    cin>>n>>m>>p;
    for(int i=0;i<n;++i)
        for(int j=0;j<m;++j)
            cin>>a[i][j];
    for(int i=0;i<m;++i)memset(f[i],0x3f,sizeof(ll)*m);
    for(int k=0;k<m;++k)f[0][k]=a[0][k]+k*p;
    for(int i=0;i<n;++i){
        if(i){
            for(int j=0;j<m;++j)
                for(int k=0;k<m;++k)
                    f[j][k]=g[j]+a[i][(j+k)%m]+k*p;
        }
        for(int j=1;j<m;++j)
            for(int k=0;k<m;++k)
                f[j][k]=min(f[j][k],f[j-1][k]+a[i][(j+k)%m]);
        memset(g,0x3f,sizeof(ll)*m);
        for(int j=0;j<m;++j)
            for(int k=0;k<m;++k)
                g[j]=min(g[j],f[j][k]);
    }
    cout<<g[m-1]<<'\n';
}

int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    int T;
    cin>>T;
    while(T--)solve();
}
posted @ 2024-12-21 01:40  EssnSlaryt  阅读(321)  评论(0编辑  收藏  举报