5-20ACM训练题解(2017-2018 ACM-ICPC Pacific Northwest Regional Contest)
A-odd Palindrome Gym - 101615A
签到,判断是否有两个相邻的字符相同即可
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #define N 105 7 using namespace std; 8 char bb[N]; 9 int n; 10 int main() 11 { 12 scanf("%s",bb+1); 13 n=strlen(bb+1); 14 for(int i=1;i<n;i++) 15 { 16 if(bb[i]==bb[i+1]) 17 { 18 printf("Or not."); 19 return 0; 20 } 21 } 22 printf("Odd.\n"); 23 return 0; 24 }
B-Enlarging Enthusiasm Gym - 101615B
很妙的一个状压DP题
最初设想的状态是f[x][pr][la][sum],代表当前已经宣布了x状态的人,上一个宣布的是pr,给pr加了la分,还剩下sum分,这样虽然能够表示出所有状态,但是显然空间和时间复杂度都不行,所以我们要想办法消掉一维。
通过思考我们会发现一个很美妙的性质,如果让a[y]紧接着a[x]+q[x]之后宣布那么他要加的值就是max(a[x]+q[x]+1-a[y],q[x])。那我们可以提出来q[x],得到q[x]+max(a[x]+1-a[y],0),也就是说如果我们每次将q[x]分给x的时候也将它分给其他尚未被宣布的人,那么每次将y放在x之后宣布要花费的值就是max(a[x]-a[y]+1,0)*cnt,cnt为此时还未被宣布的人数。之后用记忆化搜索就可以了
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #define N (1<<12) 7 using namespace std; 8 int n,K; 9 int a[N]; 10 long long f[N][13][701]; 11 long long dfs(int x,int pr,int sum) 12 { 13 if(sum<0)return 0; 14 if(x==((1<<n)-1))return 1; 15 if(f[x][pr][sum]!=-1)return f[x][pr][sum]; 16 int cnt=0; 17 f[x][pr][sum]=0; 18 for(int i=1;i<=12;i++) 19 { 20 if((1<<(i-1))&x) cnt++; 21 } 22 for(int i=1;i<=12;i++) 23 { 24 if((1<<(i-1))&x)continue; 25 f[x][pr][sum]+=dfs(x|(1<<(i-1)),i,sum-max(0,a[pr]-a[i]+1)*(n-cnt)); 26 } 27 return f[x][pr][sum]; 28 } 29 int main() 30 { 31 scanf("%d%d",&n,&K); 32 memset(f,-1,sizeof(f)); 33 int mx=0; 34 for(int i=1;i<=n;i++) 35 { 36 scanf("%d",&a[i]); 37 mx=max(mx,a[i]); 38 } 39 long long ans=0; 40 for(int i=1;i<=n;i++) 41 { 42 if(a[i]==mx) continue; 43 ans+=dfs((1<<(i-1)),i,K-(mx-a[i]+1)*n); 44 } 45 printf("%lld\n",ans); 46 return 0; 47 }
D-Rainbow roads Gym - 101615D
树上DP
我们设f[x][0]表示是否所有以x为端点,向下的路径时候都合法,如果都合法则为1,否则为0,设f[x][1]表示是否所有以x为端点,且经过x的父亲的路径是否都合法,如果两者都为1那么x就合法,具体转移很简单,唯一需要注意的就是如果x向某个儿子的边的颜色和向他父亲的边的颜色相同的话那么他的兄弟节点f[ ][1]都为0。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #define N 50005 7 using namespace std; 8 int n; 9 int f[N][2],zz,a[N]; 10 struct ro{ 11 int to,next,l; 12 }road[N*2]; 13 void build(int x,int y,int z) 14 { 15 zz++; 16 road[zz].to=y; 17 road[zz].next=a[x]; 18 road[zz].l=z; 19 a[x]=zz; 20 } 21 int fa[N]; 22 int tmp[N]; 23 int js[N],bj[N]; 24 bool ans[N]; 25 void dfs(int x,int z) 26 { 27 f[x][0]=1; 28 f[x][1]=1; 29 ans[x]=1; 30 for(int i=a[x];i;i=road[i].next) 31 { 32 int y=road[i].to; 33 if(y==fa[x])continue; 34 fa[y]=x; 35 36 dfs(y,road[i].l); 37 if(road[i].l==z) 38 { 39 f[fa[x]][0]=0; 40 bj[x]=1; 41 f[y][1]=0; 42 } 43 if(!f[y][0])f[x][0]=0; 44 } 45 if(!f[x][0]) ans[x]=0; 46 js[fa[x]]+=bj[x]; 47 } 48 void dfs2(int x,int z) 49 { 50 int cnt1=0,cnt2=0; 51 for(int i=a[x];i;i=road[i].next) 52 { 53 int y=road[i].to; 54 if(y==fa[x])continue; 55 cnt1++; 56 if(f[y][0]) cnt2++; 57 } 58 for(int i=a[x];i;i=road[i].next) 59 { 60 int y=road[i].to; 61 if(y==fa[x])continue; 62 if(!f[x][1]||cnt1-1!=cnt2-f[y][0]||js[x]-bj[y]) 63 { 64 f[y][1]=0; 65 } 66 } 67 tmp[z]++; 68 for(int i=a[x];i;i=road[i].next) 69 { 70 int y=road[i].to; 71 if(y==fa[x])continue; 72 tmp[road[i].l]++; 73 } 74 for(int i=a[x];i;i=road[i].next) 75 { 76 int y=road[i].to; 77 if(y==fa[x])continue; 78 if(tmp[road[i].l]>=2) f[y][1]=0; 79 } 80 tmp[z]--; 81 for(int i=a[x];i;i=road[i].next) 82 { 83 int y=road[i].to; 84 if(y==fa[x])continue; 85 tmp[road[i].l]--; 86 } 87 for(int i=a[x];i;i=road[i].next) 88 { 89 int y=road[i].to; 90 if(y==fa[x])continue; 91 dfs2(y,road[i].l); 92 } 93 } 94 int main() 95 { 96 scanf("%d",&n); 97 for(int i=1;i<n;i++) 98 { 99 int x,y,z; 100 scanf("%d%d%d",&x,&y,&z); 101 build(x,y,z); 102 build(y,x,z); 103 } 104 dfs(1,0); 105 dfs2(1,0); 106 int js=0; 107 for(int i=1;i<=n;i++) 108 { 109 if(f[i][1]==0||f[i][0]==0) ans[i]=0; 110 if(ans[i]) js++; 111 } 112 printf("%d\n",js); 113 for(int i=1;i<=n;i++) 114 { 115 if(ans[i])printf("%d\n",i); 116 } 117 return 0; 118 }
I-longlongstrings Gym - 101615I
大模拟
我们对于每一个串这么记录他的最终状态:
原来的串中那些位置的元素被删了
新增的元素在所有操作完了之后的串中下标为多少,具体是什么。
然后将两个串的状态进行比较就好了,由于n很小,所以直接n^2模拟就可以。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #define N 2005 7 using namespace std; 8 char bb[20]; 9 long long f[4][N]; 10 int cnt[4]; 11 long long g[4][N][2]; 12 long long F[2][N],G[2][N][2]; 13 int main() 14 { 15 int js=0; 16 while(js!=2) 17 { 18 //scanf("%c ",&bb); 19 cin>>bb; 20 if(bb[0]=='E') 21 { 22 js++; 23 continue; 24 } 25 cnt[js]++; 26 if(bb[0]=='D') 27 { 28 29 f[js][cnt[js]]=0; 30 long long x; 31 scanf("%lld",&x); 32 g[js][cnt[js]][0]=x; 33 } 34 else 35 { 36 long long x; 37 scanf("%lld",&x); 38 cin>>bb; 39 f[js][cnt[js]]=1; 40 g[js][cnt[js]][0]=x; 41 g[js][cnt[js]][1]=(bb[0]-'A'+1); 42 } 43 } 44 for(int i=1;i<=cnt[0];i++) 45 { 46 if(f[0][i]==0) 47 { 48 long long x=g[0][i][0]; 49 bool yx=1; 50 for(int j=1;j<=G[0][0][0];j++) 51 { 52 if(G[0][j][0]==g[0][i][0]) 53 { 54 G[0][j][0]=-1; 55 yx=0; 56 break; 57 } 58 } 59 if(yx) 60 { 61 for(int j=i-1;j;j--) 62 { 63 if(f[0][j]==0) 64 { 65 if(g[0][j][0]<=x) 66 { 67 x++; 68 } 69 } 70 else 71 { 72 if(g[0][j][0]<=x) 73 { 74 x--; 75 } 76 } 77 } 78 F[0][0]++; 79 F[0][F[0][0]]=x; 80 } 81 82 for(int j=1;j<=G[0][0][0];j++) 83 { 84 if(G[0][j][0]!=-1&&G[0][j][0]>=g[0][i][0]) 85 { 86 G[0][j][0]--; 87 } 88 } 89 } 90 else 91 { 92 for(int j=1;j<=G[0][0][0];j++) 93 { 94 if(G[0][j][0]!=-1&&G[0][j][0]>=g[0][i][0]) 95 { 96 G[0][j][0]++; 97 } 98 } 99 G[0][0][0]++; 100 G[0][G[0][0][0]][0]=g[0][i][0]; 101 G[0][G[0][0][0]][1]=g[0][i][1]; 102 } 103 } 104 105 for(int i=1;i<=cnt[1];i++) 106 { 107 if(f[1][i]==0) 108 { 109 long long x=g[1][i][0]; 110 bool yx=1; 111 for(int j=1;j<=G[1][0][0];j++) 112 { 113 if(G[1][j][0]==g[1][i][0]) 114 { 115 G[1][j][0]=-1; 116 yx=0; 117 break; 118 } 119 } 120 if(yx) 121 { 122 for(int j=i-1;j;j--) 123 { 124 if(f[1][j]==0) 125 { 126 if(g[1][j][0]<=x) 127 { 128 x++; 129 } 130 } 131 else 132 { 133 if(g[1][j][0]<=x) 134 { 135 x--; 136 } 137 } 138 } 139 F[1][0]++; 140 F[1][F[1][0]]=x; 141 } 142 143 for(int j=1;j<=G[1][0][0];j++) 144 { 145 if(G[1][j][0]!=-1&&G[1][j][0]>=g[1][i][0]) 146 { 147 G[1][j][0]--; 148 } 149 } 150 } 151 else 152 { 153 for(int j=1;j<=G[1][0][0];j++) 154 { 155 if(G[1][j][0]!=-1&&G[1][j][0]>=g[1][i][0]) 156 { 157 G[1][j][0]++; 158 } 159 } 160 G[1][0][0]++; 161 G[1][G[1][0][0]][0]=g[1][i][0]; 162 G[1][G[1][0][0]][1]=g[1][i][1]; 163 } 164 } 165 sort(F[0]+1,F[0]+F[0][0]+1); 166 sort(F[1]+1,F[1]+F[1][0]+1); 167 if(F[0][0]!=F[1][0]) 168 { 169 printf("1\n"); 170 return 0; 171 } 172 for(int i=1;i<=F[0][0];i++) 173 { 174 if(F[0][i]!=F[1][i]) 175 { 176 printf("1\n"); 177 exit(0); 178 } 179 } 180 for(int i=1;i<=G[0][0][0];i++) 181 { 182 if(G[0][i][0]==-1)continue; 183 bool yx=1; 184 for(int j=1;j<=G[1][0][0];j++) 185 { 186 if(G[0][i][0]==G[1][j][0]&&G[1][j][1]==G[0][i][1]) 187 { 188 G[1][j][0]=-1; 189 yx=0; 190 break; 191 } 192 } 193 if(yx) 194 { 195 printf("1\n"); 196 exit(0); 197 } 198 } 199 for(int i=1;i<=G[1][0][0];i++) 200 { 201 if(G[1][i][0]!=-1) 202 { 203 printf("1\n"); 204 exit(0); 205 } 206 } 207 printf("0\n"); 208 return 0; 209 }
J-Grid coloring Gym - 101615J
DP
我们设f[x][y]为x行最后一个蓝色放在第y列时的方案数,f[x][y]可以从f[x-1][y~m]直接转移过来,提前预处理一下每一行具体是哪个区间可以放蓝色方块然后转移就可以了(为什么n这么小……我觉得n=4000都可以啊)
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #define N 35 7 using namespace std; 8 int n,m; 9 char bb[N]; 10 int ma[N][N],L[N],R[N]; 11 long long f[N][N]; 12 int main() 13 { 14 scanf("%d%d",&n,&m); 15 for(int i=1;i<=n;i++) 16 { 17 scanf("%s",bb+1); 18 for(int j=1;j<=m;j++) 19 { 20 if(bb[j]=='B') ma[i][j]=1; 21 else if(bb[j]=='R') ma[i][j]=2; 22 } 23 } 24 for(int i=1;i<=n;i++) 25 { 26 L[i]=0,R[i]=m; 27 for(int j=1;j<=m;j++) 28 { 29 if(ma[i][j]==2) 30 { 31 R[i]=j-1; 32 break; 33 } 34 } 35 for(int j=m;j;j--) 36 { 37 if(ma[i][j]==1) 38 { 39 L[i]=j; 40 break; 41 } 42 } 43 } 44 for(int i=L[1];i<=R[1];i++) 45 { 46 f[1][i]=1; 47 } 48 for(int i=2;i<=n;i++) 49 { 50 for(int j=L[i];j<=R[i];j++) 51 { 52 for(int k=j;k<=m;k++) 53 { 54 f[i][j]+=f[i-1][k]; 55 } 56 } 57 } 58 59 long long ans=0; 60 for(int i=0;i<=m;i++) ans+=f[n][i]; 61 printf("%lld\n",ans); 62 return 0; 63 }