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();
}