Codeforces Round #663 (Div. 2)訓練小結
阿新 • • 發佈:2020-10-08
Virtual participation
A. Suborrays
觀察發現任何排列均滿足題意。
#include<bits/stdc++.h> using namespace std; int N; int main(){ ios::sync_with_stdio(0); cin.tie(0); int T;cin>>T; while(T--){ cin>>N; for(int i=1;i<=N;++i) printf("%d ",i); puts(""); } return 0; }
B. Fix You
由於要求從任意位置都能走到右下角,只要讓最後一行均為“R”,最後一列均為“D”即可。可以證明這是最優解。
#include<bits/stdc++.h> using namespace std; int N,M,ans; char A[110][110]; int main(){ ios::sync_with_stdio(0); cin.tie(0); int T;cin>>T; while(T--){ ans=0; cin>>N>>M; for(int i=1;i<=N;++i) cin>>A[i]+1; for(int i=1;i<N;++i) if(A[i][M]!='D') ++ans; for(int j=1;j<M;++j) if(A[N][j]!='R') ++ans; printf("%d\n",ans); } return 0; }
C. Cyclic Permutations
組合數學。
觀察發現,只有最大數的左側升序,右側降序的排列符合題意。
#include<bits/stdc++.h> using namespace std; const int mod=1e9+7; int N,fac[1000010],ifac[1000010]; long long ans; int C(int n,int m){ if(n<m)return 0; return 1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod; } int qpow(int base,int b){ int res=1; while(b){ if(b&1)res=1ll*res*base%mod; base=1ll*base*base%mod; b>>=1; } return res; } int main(){ ios::sync_with_stdio(0); cin.tie(0); cin>>N; fac[0]=1; for(int i=1;i<=N;++i) fac[i]=1ll*fac[i-1]*i%mod; ifac[N]=qpow(fac[N],mod-2); for(int i=N;i>=1;--i) ifac[i-1]=1ll*ifac[i]*i%mod; ans=fac[N]; for(int i=1;i<=N;++i) ans=(ans-C(N-1,i-1)+mod)%mod; printf("%lld\n",ans); return 0; }
D. 505
狀壓DP。
當 \(N\ge 4\) 且 \(M\ge 4\) 時,不存在解。所以行/列不超過3,且只需要考慮 \(2\times 2\) 的子矩陣即可。顯然可以狀壓DP。記 \(f(i,S)\) 表示“做到第 \(i\) 行(列),當前行(列)的01序列為 \(S\) ”的最少步驟數。
#include<bits/stdc++.h>
using namespace std;
int N,M,A[1000010],B[5],ans;
int F[1000010][10];
char str[1000010];
int getPos(int x,int y){
return x*M+y;
}
int isRight(int k1,int k2,int x){
memset(B,0,sizeof(B));
for(int i=0;i<x;++i,k1>>=1,k2>>=1)
B[i]=(k1&1)+(k2&1);
for(int i=1;i<x;++i)
if((B[i-1]+B[i])%2==0)
return 0;
return 1;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin>>N>>M;ans=1e6;
for(int i=0;i<N;++i){
cin>>str;
for(int j=0;j<M;++j)
A[getPos(i,j)]=str[j]-'0';
}
if(N>=4&&M>=4)puts("-1");
else{
int tmp;
if(N<2||M<2)puts("0");
else if(N<4){
for(int j=0;j<M;++j)
for(int k=0;k<(1<<N);++k)
F[j][k]=1e6;
for(int k=0;k<(1<<N);++k){
F[0][k]=0;
for(int i=0;i<N;++i)
F[0][k]+=(A[getPos(i,0)]!=((k>>i)&1));
}
for(int j=1;j<M;++j)
for(int k1=0;k1<(1<<N);++k1)
for(int k2=0;k2<(1<<N);++k2)
if(isRight(k1,k2,N)){
tmp=0;
for(int i=0;i<N;++i)
tmp+=(A[getPos(i,j)]!=((k2>>i)&1));
F[j][k2]=min(F[j][k2],F[j-1][k1]+tmp);
}
for(int k=0;k<(1<<N);++k)
ans=min(ans,F[M-1][k]);
printf("%d\n",ans);
}
else if(M<4){
for(int i=0;i<N;++i)
for(int k=0;k<(1<<M);++k)
F[i][k]=1e6;
for(int k=0;k<(1<<M);++k){
F[0][k]=0;
for(int j=0;j<M;++j)
F[0][k]+=(A[getPos(0,j)]!=((k>>j)&1));
}
for(int i=1;i<N;++i)
for(int k1=0;k1<(1<<M);++k1)
for(int k2=0;k2<(1<<M);++k2)
if(isRight(k1,k2,M)){
tmp=0;
for(int j=0;j<M;++j)
tmp+=(A[getPos(i,j)]!=((k2>>j)&1));
F[i][k2]=min(F[i][k2],F[i-1][k1]+tmp);
}
for(int k=0;k<(1<<M);++k)
ans=min(ans,F[N-1][k]);
printf("%d\n",ans);
}
}
return 0;
}
總結
整體做的還不錯。