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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
Problem K
Solution:
留坑。
Problem L
Solution:
留坑。

浙公网安备 33010602011771号