Codeforces Round #369 (Div. 2) 套题
A:模拟水题不说
#include <iostream> #include <string.h> #include <algorithm> #include <stdio.h> #include <math.h> #include <bitset> using namespace std; typedef long long LL; const int N= 1e3+5; char s[N][10]; int main(){ int n; scanf("%d",&n); for(int i=1;i<=n;++i)scanf("%s",s[i]+1); bool flag=false; for(int i=1;i<=n;++i){ if(s[i][1]==s[i][2]&&s[i][1]=='O'){ flag=true; s[i][1]=s[i][2]='+'; break; } if(s[i][4]==s[i][5]&&s[i][4]=='O'){ flag=true; s[i][4]=s[i][5]='+'; break; } } if(flag)printf("YES\n"); else printf("NO\n"); if(flag) for(int i=1;i<=n;++i)printf("%s\n",s[i]+1); return 0; }
B:n*n的方阵,只有一个位置是未填数的,然后问填数以后,行和列和主副对角线和相等
O(n^2)模拟即可(这题FST了,由于输出格式不太对,对了这个也许能上更多分吧)
#include <iostream> #include <string.h> #include <algorithm> #include <stdio.h> #include <math.h> #include <bitset> using namespace std; typedef long long LL; const int N= 5e2+5; LL a[N][N]; int main(){ int n,x,y; scanf("%d",&n); for(int i=1;i<=n;++i){ for(int j=1;j<=n;++j){ scanf("%I64d",&a[i][j]); if(a[i][j]==0){ x=i; y=j; } } } if(n==1){ printf("1\n"); return 0; } LL sum=0; if(x==1) for(int i=1;i<=n;++i)sum+=a[2][i]; else for(int i=1;i<=n;++i)sum+=a[1][i]; LL ret=-1; for(int i=1;i<=n;++i){ LL tmp=0; for(int j=1;j<=n;++j) tmp+=a[i][j]; if(i==x){ if(tmp<sum){ if(ret!=-1&&ret!=sum-tmp){ printf("-1\n"); return 0; } else ret=sum-tmp; } else { printf("-1\n"); return 0; } } else{ if(sum!=tmp){ printf("-1\n"); return 0; } } } for(int j=1;j<=n;++j){ LL tmp=0; for(int i=1;i<=n;++i) tmp+=a[i][j]; if(j==y){ if(tmp<sum){ if(ret!=-1&&ret!=sum-tmp){ printf("-1\n"); return 0; } else ret=sum-tmp; } else { printf("-1\n"); return 0; } } else{ if(sum!=tmp){ printf("-1\n"); return 0; } } } LL tmp=0; for(int i=1;i<=n;++i)tmp+=a[i][i]; if(x==y){ if(tmp<sum){ if(ret!=-1&&ret!=sum-tmp){ printf("-1\n"); return 0; } else ret=sum-tmp; } else { printf("-1\n"); return 0; } } else{ if(sum!=tmp){ printf("-1\n"); return 0; } } tmp=0; for(int i=1;i<=n;++i)tmp+=a[i][n+1-i]; if(x+y==n+1){ if(tmp<sum){ if(ret!=-1&&ret!=sum-tmp){ printf("-1\n"); return 0; } else ret=sum-tmp; } else { printf("-1\n"); return 0; } } else{ if(sum!=tmp){ printf("-1\n"); return 0; } } printf("%I64d\n",ret); return 0; }
C:赛场上写了个裸的O(n^4)的dp,dp[i][j][k]代表当前是第i个数,这个数是j,分成k块的最小值
由于是时限是2s,而且是CF评测机,不虚
#include <iostream> #include <string.h> #include <algorithm> #include <stdio.h> #include <math.h> #include <bitset> using namespace std; typedef long long LL; const int N= 1e2+5; LL dp[N][N][N]; LL p[N][N]; int a[N]; int main(){ int n,m,k; scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=n;++i)scanf("%d",&a[i]); for(int i=1;i<=n;++i){ for(int j=1;j<=m;++j) scanf("%I64d",&p[i][j]); } memset(dp,-1,sizeof(dp)); if(a[1]!=0)dp[1][a[1]][1]=0; else{ for(int i=1;i<=m;++i) dp[1][i][1]=p[1][i]; } for(int i=2;i<=n;++i){ int lim=min(k,i); if(a[i]!=0){ for(int j=1;j<=lim;++j){ for(int c=1;c<=m;++c){ if(dp[i-1][c][j-1]!=-1&&a[i]!=c){ if(dp[i][a[i]][j]==-1)dp[i][a[i]][j]=dp[i-1][c][j-1]; else dp[i][a[i]][j]=min(dp[i][a[i]][j],dp[i-1][c][j-1]); } if(dp[i-1][c][j]!=-1&&a[i]==c) if(dp[i][a[i]][j]==-1)dp[i][a[i]][j]=dp[i-1][c][j]; else dp[i][a[i]][j]=min(dp[i][a[i]][j],dp[i-1][c][j]); } } continue; } for(int x=1;x<=m;++x){ for(int j=1;j<=lim;++j){ for(int c=1;c<=m;++c){ if(dp[i-1][c][j-1]!=-1&&x!=c){ if(dp[i][x][j]==-1)dp[i][x][j]=dp[i-1][c][j-1]+p[i][x]; else dp[i][x][j]=min(dp[i][x][j],dp[i-1][c][j-1]+p[i][x]); } if(dp[i-1][c][j]!=-1&&x==c) if(dp[i][x][j]==-1)dp[i][x][j]=dp[i-1][c][j]+p[i][x]; else dp[i][x][j]=min(dp[i][x][j],dp[i-1][c][j]+p[i][x]); } } } } LL ret=-1; for(int i=1;i<=m;++i) if(dp[n][i][k]!=-1){ if(ret==-1)ret=dp[n][i][k]; else ret=min(ret,dp[n][i][k]); } printf("%I64d\n",ret); return 0; }
D:这种题很常见,有向环套树,看每个环的反转方案,是2^k-2(k是边数,必须翻一个,不能全翻)
剩下的树上的边翻不翻都可以是2^tot,tot代表树边,然后都乘起来即可
#include <iostream> #include <string.h> #include <algorithm> #include <stdio.h> #include <math.h> #include <bitset> using namespace std; typedef long long LL; const int N = 2e5+5; const LL mod = 1e9+7; int to[N],n; int vis[N]; LL qpow(LL x,LL y){ LL ret=1; while(y){ if(y&1)ret=ret*x%mod; y>>=1; x=x*x%mod; } return ret; } int main(){ scanf("%d",&n); for(int i=1;i<=n;++i)scanf("%d",&to[i]); LL z=n,ret=1; for(int i=1;i<=n;++i){ if(vis[i])continue; int x=i; while(!vis[x]){ vis[x]=i; x=to[x]; } if(vis[x]!=i)continue; int t=x,cnt=0; do{ ++cnt; t=to[t]; }while(t!=x); z-=cnt; ret=1ll*ret*((qpow(2,cnt)-2+mod)%mod)%mod; } ret=ret*qpow(2,z)%mod; printf("%I64d\n",ret); return 0; }
E:考虑正难则反,概率等于1-A(k,2^n)/2^(nk),然后发现最大公约数只能是2^i,约分即可
#include <iostream> #include <string.h> #include <algorithm> #include <stdio.h> #include <math.h> #include <bitset> using namespace std; typedef long long LL; const int N = 2e5+5; const LL mod = 1e6+3; LL qpow(LL x,LL y){ LL ret=1; while(y){ if(y&1)ret=ret*x%mod; x=x*x%mod;y>>=1; } return ret; } int main(){ LL n,k; scanf("%I64d%I64d",&n,&k); if(n<=62&&k>1ll<<n){ printf("1 1\n"); return 0; } LL num=0; for(LL i=k-1;i;i>>=1){ num+=i/2; } LL b=1,a=qpow(2,n); for(LL i=1;i<=k-1;++i){ LL tmp=(a-i+mod)%mod; b=b*tmp%mod; if(tmp==0)break; } LL inv=qpow(qpow(2,num),mod-2); a=qpow(a,k-1); a=a*inv%mod; b=b*inv%mod; b=(a-b+mod)%mod; printf("%I64d %I64d\n",b,a); return 0; }