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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

 

posted @ 2020-05-21 12:10  Hzoi_joker  阅读(227)  评论(0编辑  收藏  举报