2017 ACM-ICPC SEERC Solutions

题目链接:https://vj.e949.cn/85a2d6bb6739f64d26b94c70567e9a6c?v=1540370665

Problem A

Solution:

  这是一个比较显然的 \(O(nk)\) 的dp。比较坑的是题目中的数据范围,\(n\) 最大有 \(100,000\)。用滚动数组可以避免空间炸掉。

 1 #include<bits/stdc++.h>
 2 #define rep(i,a,n) for(int i=a;i<=n;i++)
 3 #define maxn 100000
 4 #define mod 1000000007
 5 using namespace std;
 6 typedef long long ll;
 7 int sum[2][maxn+5];
 8 int h[26];
 9 char s[maxn+5],t[maxn+5];
10 int main()
11 {
12     int k,n;
13     while(~scanf("%d%d",&k,&n))
14     {
15         rep(i,0,25) scanf("%d",&h[i]);
16         scanf("%s",t+1);
17         scanf("%s",s+1);
18         
19         rep(i,0,n) sum[0][i]=1;
20         rep(j,1,k)
21         {
22             sum[j&1][0]=0;
23             rep(i,1,n)
24             {
25                 int x=(j>1)?h[t[j-1]-'A']+1:1;
26                 int y=0;
27                 if(x<=i && t[j]==s[i]) y=sum[(j-1)&1][i-x];
28                 sum[j&1][i]=(sum[j&1][i-1]+y)%mod;
29             }
30         }
31         printf("%d\n",sum[k&1][n]);
32     }
33     return 0;
34 }
View Code

 

Problem B

Solution:

  首先注意到石头落下来的顺序不影响答案。然后可以用dp来做此题:\(dp[i]\) 表示第 \(i\) 个格子最后是空的的方法数,转移时枚举前一个空格子 \(j\) 的位置。

  但是这样子做的时间复杂度是 \(O(m+n^2)\) 的。不过观察的转移方程发现下标的规律后转移就可以优化到 \(O(1)\) 了,所以最后的时间复杂度是 \(O(m+n)\)。

 1 #include<bits/stdc++.h>
 2 #define rep(i,a,n) for(int i=a;i<=n;i++)
 3 #define maxn 2000000
 4 #define mod 1000000007
 5 using namespace std;
 6 typedef long long ll;
 7 ll dp[maxn+5],sum[maxn+5];
 8 int cnt[maxn+5],s[maxn+5];
 9 int main()
10 {
11     int n,m;
12     scanf("%d%d",&n,&m);
13     rep(i,1,m)
14     {
15         int x;
16         scanf("%d",&x);
17         cnt[x]++;
18     }
19     dp[0]=1;
20     sum[0+m]=1;
21     rep(i,1,n+1) s[i]=s[i-1]+cnt[i];
22     rep(i,1,n+1)
23     {
24         if(cnt[i]) continue;
25         dp[i]=(dp[i]+sum[i-s[i]-1+m])%mod;
26         sum[i-s[i]+m]=(sum[i-s[i]+m]+dp[i])%mod;
27     }
28     printf("%lld\n",dp[n+1]);
29     return 0;
30 }
View Code

 

Problem C

Solution:

  本质是要求一个颜色之间的拓扑序。这类问题都可以用倍增/线段树优化连边。本题可以先对每种颜色求出极长链之后倍增优化建图。最后的时间复杂度是 \(O((m+n) \log n)\) 的。(See Code 1)

  不过我最开始处理这个拓扑序的想法不是建图跑拓扑排序,而是直接用set维护颜色块。合并时用启发式合并。时间复杂度是 \(O(m \log n +n \log ^2 n )\) 的。然而跑得反而更快?还更好写?(See Code 2)

  1 #include<bits/stdc++.h>
  2 #define rep(i,a,n) for(int i=a;i<=n;i++)
  3 #define per(i,a,n) for(int i=n;i>=a;i--)
  4 #define maxn 100000
  5 #define pb push_back
  6 using namespace std;
  7 int c[maxn+5];
  8 int dep[maxn+5],anc[17][maxn+5],id[17][maxn+5],lg[maxn+5];
  9 vector<int> to[maxn*20+5],e[maxn+5],L[maxn+5],ch[maxn+5],ans;
 10 int deg[maxn*20+5],q[maxn*20+5];
 11 void dfs(int now,int fa)
 12 {
 13     int l=e[now].size();
 14     rep(i,0,l-1)
 15     {
 16         int v=e[now][i];
 17         if(v==fa) continue;
 18         dep[v]=dep[now]+1;
 19         anc[0][v]=now;
 20         dfs(v,now);
 21     }
 22 }
 23 
 24 int swim(int x,int h)
 25 {
 26     int i=0;
 27     while(h)
 28     {
 29         if(h&1) x=anc[i][x];
 30         h>>=1;
 31         i++;
 32     }
 33     return x;
 34 }
 35 int dist(int x,int y,int p)
 36 {
 37     return dep[x]+dep[y]-2*dep[p];
 38 }
 39 int findd(int x,int y,int p,int d)
 40 {
 41     if(d<=dep[x]-dep[p]) return swim(x,d);
 42     else return swim(y,dist(x,y,p)-d);
 43 }
 44 int lca(int x,int y)
 45 {
 46     if(dep[y]>dep[x]) swap(x,y);
 47     x=swim(x,dep[x]-dep[y]);
 48     if(x==y) return x;
 49     per(i,0,16)
 50     {
 51         if(anc[i][x]==anc[i][y]) continue;
 52         x=anc[i][x];y=anc[i][y];
 53     }
 54     return anc[0][x];
 55 }
 56 void add(int color,int x,int y)
 57 {
 58     int p=lca(x,y);
 59     if(dist(x,y,p)==1) return;
 60     int fx=findd(x,y,p,1);
 61     int fy=findd(y,x,p,1);
 62     x=fx;y=fy;
 63     if(x==y)
 64     {
 65         to[c[x]].pb(color);
 66     }
 67     p=lca(x,y);
 68     if(x!=p)
 69     {
 70         int k=lg[dep[x]-dep[p]];
 71         to[id[k][x]].pb(color);
 72         x=swim(x,dep[x]-dep[p]-(1<<k));
 73         to[id[k][x]].pb(color);
 74     }
 75     if(y!=p)
 76     {
 77         int k=lg[dep[y]-dep[p]];
 78         to[id[k][y]].pb(color);
 79         y=swim(y,dep[y]-dep[p]-(1<<k));
 80         to[id[k][y]].pb(color);
 81     }
 82 }
 83 bool cmp(int x,int y)
 84 {
 85     return dep[x]>dep[y];
 86 }
 87 int main()
 88 {
 89     rep(i,2,maxn) lg[i]=lg[i>>1]+1;
 90     int n,m;
 91     scanf("%d%d",&n,&m);
 92     rep(i,1,n)
 93     {
 94         scanf("%d",&c[i]);
 95         L[c[i]].push_back(i);
 96     }
 97     rep(i,1,n-1)
 98     {
 99         int u,v;scanf("%d%d",&u,&v);
100         e[u].push_back(v);
101         e[v].push_back(u);
102     }
103     dfs(1,0);
104     int tot=m;
105     rep(i,1,16) rep(j,1,n) anc[i][j]=anc[i-1][anc[i-1][j]];
106     rep(i,0,16) rep(j,1,n) id[i][j]=++tot;
107     rep(j,1,n)
108     {
109         to[c[j]].pb(id[0][j]);
110         if(anc[0][j]) to[c[anc[0][j]]].pb(id[0][j]);
111     }
112     rep(i,1,16) rep(j,1,n)
113     {
114         if(anc[i-1][j]) to[id[i-1][j]].pb(id[i][j]);
115         if(anc[i-1][anc[i-1][j]]) to[id[i-1][anc[i-1][j]]].pb(id[i][j]);
116     }
117     rep(i,1,m) sort(L[i].begin(),L[i].end(),cmp);
118     rep(i,1,m)
119     {
120         if(L[i].empty()) continue;
121         int l=L[i].size(),u=L[i][0];
122         ch[i].resize(l);
123         int LL=0,R=l;
124         rep(j,0,l-1)
125         {
126             int v=L[i][j];
127             if(swim(u,dep[u]-dep[v])==v) ch[i][LL++]=v;
128             else ch[i][--R]=v;
129         }
130         rep(j,1,l-1) add(i,ch[i][j-1],ch[i][j]);
131     }
132     rep(i,1,tot)
133     {
134         int l=to[i].size();
135         rep(j,0,l-1)
136         {
137             int v=to[i][j];
138             deg[v]++;
139         }
140     }
141     int rear=-1;
142     rep(i,1,m) if(L[i].empty()) printf("%d 1 1\n",i);
143     rep(i,1,tot) if(deg[i]==0) q[++rear]=i;
144     rep(front,0,rear)
145     {
146         int v=q[front];
147         if(v<=m && !L[v].empty()) ans.pb(v);
148         int l=to[v].size();
149         rep(i,0,l-1)
150         {
151             int u=to[v][i];
152             if(--deg[u]==0) q[++rear]=u;
153         }
154     }
155     int l=ans.size();
156     per(i,0,l-1)
157     {
158         int v=ans[i];
159         printf("%d %d %d\n",v,ch[v][0],ch[v][ch[v].size()-1]);
160     }
161     return 0;
162 }
View Code 1
  1 #include<bits/stdc++.h>
  2 #define rep(i,a,n) for(int i=a;i<=n;i++)
  3 #define per(i,a,n) for(int i=n;i>=a;i--)
  4 #define maxn 100000
  5 #define pb push_back
  6 using namespace std;
  7 set<int> S[maxn+5];
  8 vector<int> e[maxn+5],L[maxn+5];
  9 int dep[maxn+5];
 10 int edge[maxn+5][2],c[maxn+5],cnt[maxn+5];
 11 int anc[maxn+5][20];
 12 int fa[maxn+5],ok[maxn+5];
 13 bool cmp(int x,int y){return dep[x]>dep[y];}
 14 void dfs(int now,int fa)
 15 {
 16     int l=e[now].size();
 17     rep(i,0,l-1)
 18     {
 19         int v=e[now][i];
 20         if(v==fa) continue;
 21         dep[v]=dep[now]+1;
 22         anc[v][0]=now;
 23         dfs(v,now);
 24     }
 25 }
 26 int rear=-1;
 27 int q[maxn+5];
 28 int getfa(int x)
 29 {
 30     if(fa[x]==x) return x;
 31     return fa[x]=getfa(fa[x]);
 32 }
 33 void Merge(int x,int y)
 34 {
 35     int fx=getfa(x);
 36     int fy=getfa(y);
 37     if(S[fx].size()<S[fy].size()) swap(fx,fy);
 38     for(set<int>::iterator it=S[fy].begin();it!=S[fy].end();it++)
 39     {
 40         int tmp=*it;
 41         if(S[fx].find(tmp)==S[fx].end()) S[fx].insert(tmp);
 42         else if(cnt[tmp]>1)
 43         {
 44             if(--cnt[tmp]==1) q[++rear]=tmp;
 45         }
 46     }
 47     fa[fy]=fx;
 48 }
 49 void add(int x,int cy)
 50 {
 51     int fx=getfa(x);
 52     if(S[fx].find(cy)==S[fx].end()) S[fx].insert(cy);
 53     else if(cnt[cy]>1)
 54     {
 55         if(--cnt[cy]==1) q[++rear]=cy;
 56     }
 57 }
 58 int swim(int x,int h)
 59 {
 60     int i=0;
 61     while(h)
 62     {
 63         if(h&1) x=anc[x][i];
 64         i++;
 65         h>>=1;
 66     }
 67     return x;
 68 }
 69 int main()
 70 {
 71     int n,m;
 72     scanf("%d%d",&n,&m);
 73     rep(i,1,n)
 74     {
 75         scanf("%d",&c[i]);
 76         L[c[i]].pb(i);
 77         cnt[c[i]]++;
 78         S[i].insert(c[i]);
 79     }
 80     rep(i,1,n-1)
 81     {
 82         int u,v;
 83         scanf("%d%d",&u,&v);
 84         edge[i][0]=u;
 85         edge[i][1]=v;
 86         e[u].pb(v);
 87         e[v].pb(u);
 88     }
 89     dfs(1,0);
 90     rep(i,1,18) rep(j,1,n) anc[j][i]=anc[anc[j][i-1]][i-1];
 91 
 92     rep(i,1,m) if(!L[i].empty()) sort(L[i].begin(),L[i].end(),cmp);
 93     rep(i,1,n) fa[i]=i;
 94     rep(i,1,m) if(cnt[i]==1) q[++rear]=i;
 95     rep(i,1,n-1)
 96     {
 97         int u=edge[i][0];
 98         int v=edge[i][1];
 99         if(c[u]==c[v]) Merge(u,v);
100     }
101     rep(front,0,rear)
102     {
103         int nowc=q[front],l=L[nowc].size();
104         ok[nowc]=1;
105         rep(z,0,l-1)
106         {
107             int v=L[nowc][z],ll=e[v].size();
108             rep(i,0,ll-1)
109             {
110                 int u=e[v][i];
111                 if(!ok[c[u]])
112                 {
113                     add(v,c[u]);
114                     continue;
115                 }
116                 if(getfa(u)==getfa(v)) continue;
117                 Merge(u,v);
118             }
119         }
120     }
121     rep(i,1,m) if(cnt[i]==0) printf("%d 1 1\n",i);
122     per(i,1,rear+1)
123     {
124         int cc=q[i-1];
125         int u=L[cc][0],v;
126         int l=L[cc].size();
127         rep(j,0,l-1)
128         {
129             v=L[cc][j];
130             int h=dep[u]-dep[v];
131             if(swim(u,h)!=v) break;
132         }
133         printf("%d %d %d\n",cc,u,v);
134     }
135     return 0;
136 }
View Code 2

 

Problem D

Solution:

  一列里面两个为1的位置可以认为这两个点之间连了一条边,最后求出每个连通块大小减去1,求和就是答案。

 1 #include<bits/stdc++.h>
 2 #define rep(i,a,n) for(int i=a;i<=n;i++)
 3 #define maxn 100000
 4 using namespace std;
 5 vector<int> e[maxn+5],col[maxn+5];
 6 bool mark[maxn+5];
 7 int dfs(int now)
 8 {
 9     mark[now]=1;
10     int sz=1;
11     int l=e[now].size();
12     rep(i,0,l-1)
13     {
14         int v=e[now][i];
15         if(mark[v]) continue;
16         sz+=dfs(v);
17     }
18     return sz;
19 }
20 int main()
21 {
22     int n,m;
23     scanf("%d%d",&m,&n);
24     rep(i,1,m)
25     {
26         int x;
27         scanf("%d",&x);
28         while(x--)
29         {
30             int y;
31             scanf("%d",&y);
32             col[y].push_back(i);
33         }
34     }
35     rep(i,1,n)
36     {
37         int u=col[i][0];
38         int v=col[i][1];
39         e[u].push_back(v);
40         e[v].push_back(u);
41     }
42     int ans=0;
43     rep(i,1,m) if(mark[i]==0) ans+=dfs(i)-1;
44     printf("%d\n",ans);
45 
46     return 0;
47 }
View Code

 

Problem E

Solution:

  枚举一下开头的调后按序向后贪心即可。小心TLE。

 1 #include<bits/stdc++.h>
 2 #define rep(i,a,n) for(int i=a;i<=n;i++)
 3 #define per(i,a,n) for(int i=n;i>=a;i--)
 4 #define maxn 10000000
 5 using namespace std;
 6 //char note[20][20]={"Do","Do#","Re","Re#","Mi","Fa","Fa#","Sol","Sol#","La","La#","Si"};
 7 map<string,int> M;
 8 int a[maxn+5];
 9 int ok[1<<12];
10 int main()
11 {
12     ios::sync_with_stdio(0);
13     cin.tie(0);
14 
15     M["Do"]=0;
16     M["Do#"]=1;
17     M["Re"]=2;
18     M["Re#"]=3;
19     M["Mi"]=4;
20     M["Fa"]=5;
21     M["Fa#"]=6;
22     M["Sol"]=7;
23     M["Sol#"]=8;
24     M["La"]=9;
25     M["La#"]=10;
26     M["Si"]=11;
27     int n;
28     cin>>n;
29     rep(i,1,n)
30     {
31         string s;
32         cin>>s;
33         a[i]=M[s];
34     }
35     rep(i,0,12)
36     {
37         int x=0;
38         x|=1<<(i+0)%12;
39         x|=1<<(i+2)%12;
40         x|=1<<(i+4)%12;
41         x|=1<<(i+5)%12;
42         x|=1<<(i+7)%12;
43         x|=1<<(i+9)%12;
44         x|=1<<(i+11)%12;
45         ok[x]=1;
46     }
47     per(i,0,(1<<12)-1)
48     {
49         rep(j,0,11) if(i&(1<<j)) ok[i^(1<<j)]|=ok[i];
50     }
51     int ans=n;
52     rep(i,0,11)
53     {
54         int x=0;
55         x|=1<<(i+0)%12;
56         x|=1<<(i+2)%12;
57         x|=1<<(i+4)%12;
58         x|=1<<(i+5)%12;
59         x|=1<<(i+7)%12;
60         x|=1<<(i+9)%12;
61         x|=1<<(i+11)%12;
62         int l=1,r=n,cnt=1;
63         while(l<=r)
64         {
65             if(x&(1<<a[l])) l++;
66             else break;
67         }
68         while(l<=r)
69         {
70             if(x&(1<<a[r])) r--;
71             else break;
72         }
73         int state=(1<<12)-1;
74         rep(j,l,r)
75         {
76             if(ok[state|(1<<a[j])]) state|=(1<<a[j]);
77             else
78             {
79                 state=1<<a[j];
80                 cnt++;
81                 if(cnt>=ans) break;
82             }
83         }
84         ans=min(ans,cnt);
85     }
86     cout<<ans<<endl;
87     return 0;
88 }
View Code

 

Problem F

Solution:

  队友写的于是先留个坑。口胡一下:把要变成0的先处理了再处理要变成1的就好了?

 

Problem G

Solution:

  贪心排个序就完了。

 1 #include<bits/stdc++.h>
 2 #define rep(i,a,n) for(int i=a;i<=n;i++)
 3 #define maxn 10000
 4 #define mod 1000000007
 5 using namespace std;
 6 typedef long long ll;
 7 struct node
 8 {
 9     ll a,t;
10 }d[maxn+5];
11 bool cmp(node x,node y)
12 {
13     return x.a>y.a;
14 }
15 int main()
16 {
17     int k,n;
18     scanf("%d",&n);
19     rep(i,1,n) scanf("%d%d",&d[i].a,&d[i].t);
20     ll ans1=0,ans2=0,v=0;
21     rep(i,1,n)
22     {
23         ans1+=2*v*d[i].t+d[i].a*d[i].t*d[i].t;
24         v+=d[i].a*d[i].t;
25     }
26     sort(d+1,d+n+1,cmp);
27     v=0;
28     rep(i,1,n)
29     {
30         ans2+=2*v*d[i].t+d[i].a*d[i].t*d[i].t;
31         v+=d[i].a*d[i].t;
32     }
33     ll A=ans2-ans1;
34     printf("%lld.%c\n",A/2,(A&1)?'5':'0');
35     return 0;
36 }
View Code

 

Problem H

Solution:

  留坑。

 

Problem I

Solution:

  留坑。

 

Problem J

Solution:

  博弈。直接看代码吧。

 1 #include<bits/stdc++.h>
 2 #define rep(i,a,n) for(int i=a;i<=n;i++)
 3 using namespace std;
 4 int main()
 5 {
 6     int n,x,a=0,b=0;
 7     scanf("%d",&n);
 8     rep(i,1,n)
 9     {
10         scanf("%d",&x);
11         if(x==1) a++;
12         if(x==2) b++;
13     }
14     if(a+b<n-1 || b>2) puts("Lose");
15     else if(a==n-1 || a%3) puts("Win");
16     else puts("Lose");
17     return 0;
18 }
View Code

 

Problem K

Solution:

留坑。

 

Problem L

Solution:

留坑。

 

posted @ 2020-10-20 19:35  YaoBIG  阅读(260)  评论(0)    收藏  举报