2018 ACM-ICPC南京区域赛题解
Posted songorz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2018 ACM-ICPC南京区域赛题解相关的知识,希望对你有一定的参考价值。
解题过程
开场开A,A题shl看错题意,被制止。然后开始手推A,此时byf看错E题题意,开始上机。推出A的规律后,shl看了E题,发现题意读错。写完A题,忘记判断N=0的情况,WA+1。过了A后,shl重新写E,lfw开始开J题,E题过不了样例,lfw多次起立让shl调试,然后shl拿到E的一血,lfw之后过了J。byf开始开I题,shl口胡出M做法,然后lfw和shl一起推G题。byf过了I题后,shl推出G题,byf去写。然后lfw开始计算几何,经过查错后过掉,然后shl开始开M题,过掉后还剩最后半小时,无题可做。
最后罚时很多,因为前期签到题过得太慢,A题40+分钟才过,J题1小时40分钟才过。
题解
A - Adrien and Austin
题解:给你n给石头,下标依次为1~n,然后两个人轮流取石头,每次取1~k个连续下标的石头,最后不能取得输掉比赛。问你谁会获胜。
找规律,首先,n==0时,第一个人必败。k==1时,n为奇数时先手必胜。k>1时,先手必胜.
参考代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int mod=1e9+7; 5 LL quick_pow(LL a,LL b) 6 { 7 LL ans=1; 8 while(b) 9 { 10 if(b&1) ans=ans*a%mod; 11 a=a*a%mod; 12 b>>=1; 13 } 14 return ans; 15 } 16 int main() 17 { 18 int t; 19 scanf("%d",&t); 20 int l24=quick_pow(24,mod-2); 21 while(t--) 22 { 23 int n; 24 scanf("%d",&n); 25 LL ans=1; 26 ans=ans*n%mod; 27 ans=ans*(n+1)%mod; 28 ans=ans*(n+2)%mod; 29 ans=ans*(n+3)%mod; 30 ans=ans*l24%mod; 31 printf("%lld ",ans); 32 } 33 }
B - Tournament
Unsolved.
C - Cherry and Chocolate
Unsolved.
D - Country Meow
队友写的.题解待更.
参考代码:
1 #include<bits/stdc++.h> 2 #define maxl 110 3 #define eps 1e-8 4 struct point 5 { 6 double x,y,z; 7 point(double a=0,double b=0,double c=0) 8 { 9 x=a;y=b;z=c; 10 } 11 }; 12 13 int npoint,nouter; 14 point pt[maxl],outer[4],res; 15 double radius,tmp,ans; 16 17 inline double dist(point p1,point p2) 18 { 19 double dx=p1.x-p2.x,dy=p1.y-p2.y,dz=p1.z-p2.z; 20 return (dx*dx+dy*dy+dz*dz); 21 } 22 23 inline double dot(point p1,point p2) 24 { 25 return p1.x*p2.x+p1.y*p2.y+p1.z*p2.z; 26 } 27 28 inline void ball() 29 { 30 point q[3];double m[3][3],sol[3],L[3],det; 31 int i,j; 32 res.x=res.y=res.z=radius=0; 33 switch(nouter) 34 { 35 case 1: res=outer[0];break; 36 case 2: 37 res.x=(outer[0].x+outer[1].x)/2; 38 res.y=(outer[0].y+outer[1].y)/2; 39 res.z=(outer[0].z+outer[1].z)/2; 40 radius=dist(res,outer[0]); 41 break; 42 case 3: 43 for(int i=0;i<2;i++) 44 { 45 q[i].x=outer[i+1].x-outer[0].x; 46 q[i].y=outer[i+1].y-outer[0].y; 47 q[i].z=outer[i+1].z-outer[0].z; 48 } 49 for(int i=0;i<2;i++) 50 for(int j=0;j<2;j++) 51 m[i][j]=dot(q[i],q[j])*2; 52 for(int i=0;i<2;i++) 53 sol[i]=dot(q[i],q[i]); 54 if(fabs(det=m[0][0]*m[1][1]-m[0][1]*m[1][0])<eps) 55 return; 56 L[0]=(sol[0]*m[1][1]-sol[1]*m[0][1])/det; 57 L[1]=(sol[1]*m[0][0]-sol[0]*m[1][0])/det; 58 res.x=outer[0].x+q[0].x*L[0]+q[1].x*L[1]; 59 res.y=outer[0].y+q[0].y*L[0]+q[1].y*L[1]; 60 res.z=outer[0].z+q[0].z*L[0]+q[1].z*L[1]; 61 radius=dist(res,outer[0]); 62 break; 63 case 4: 64 for(int i=0;i<3;i++) 65 { 66 q[i].x=outer[i+1].x-outer[0].x; 67 q[i].y=outer[i+1].y-outer[0].y; 68 q[i].z=outer[i+1].z-outer[0].z; 69 sol[i]=dot(q[i],q[i]); 70 } 71 for(int i=0;i<3;i++) 72 for(int j=0;j<3;j++) 73 m[i][j]=dot(q[i],q[j])*2; 74 det=m[0][0]*m[1][1]*m[2][2] 75 + m[0][1]*m[1][2]*m[2][0] 76 + m[0][2]*m[2][1]*m[1][0] 77 - m[0][2]*m[1][1]*m[2][0] 78 - m[0][1]*m[1][0]*m[2][2] 79 - m[0][0]*m[1][2]*m[2][1]; 80 if(fabs(det)<eps) return; 81 for(int j=0;j<3;j++) 82 { 83 for(int i=0;i<3;i++) 84 m[i][j]=sol[i]; 85 L[j]=(m[0][0]*m[1][1]*m[2][2] 86 +m[0][1]*m[1][2]*m[2][0] 87 +m[0][2]*m[2][1]*m[1][0] 88 -m[0][2]*m[1][1]*m[2][0] 89 -m[0][1]*m[1][0]*m[2][2] 90 -m[0][0]*m[1][2]*m[2][1])/det; 91 for(int i=0;i<3;i++) 92 m[i][j]=dot(q[i],q[j])*2; 93 } 94 res=outer[0]; 95 for(int i=0;i<3;i++) 96 { 97 res.x+=q[i].x*L[i]; 98 res.y+=q[i].y*L[i]; 99 res.z+=q[i].z*L[i]; 100 } 101 radius=dist(res,outer[0]); 102 } 103 } 104 105 inline void minball(int n) 106 { 107 ball(); 108 if(nouter<4) 109 for(int i=0;i<n;i++) 110 if(dist(res,pt[i])-radius>eps) 111 { 112 outer[nouter]=pt[i]; 113 ++nouter; 114 minball(i); 115 --nouter; 116 if(i>0) 117 { 118 point Tt=pt[i]; 119 memmove(&pt[1],&pt[0],sizeof(point)*i); 120 pt[0]=Tt; 121 } 122 } 123 } 124 125 inline double smallest_ball() 126 { 127 radius=-1; 128 for(int i=0;i<npoint;i++) 129 if(dist(res,pt[i])-radius>eps) 130 { 131 nouter=1; 132 outer[0]=pt[i]; 133 minball(i); 134 } 135 return sqrt(radius); 136 } 137 138 inline void prework() 139 { 140 for(int i=0;i<npoint;i++) 141 scanf("%lf%lf%lf",&pt[i].x,&pt[i].y,&pt[i].z); 142 } 143 144 inline void mainwork() 145 { 146 ans=smallest_ball(); 147 } 148 149 inline void print() 150 { 151 printf("%.5f ",ans); 152 } 153 154 int main() 155 { 156 while(~scanf("%d",&npoint)) 157 { 158 prework(); 159 mainwork(); 160 print(); 161 } 162 return 0; 163 }
E - Eva and Euro coins
题解:给你两个01串,然后连续k个0可以翻转为1,连续k个1可以翻转为0.问你这两个01串是否可以变成相同的串。
可以利用归约。连续k个0或1可以归约掉。最后判断是否相同即可。
参考代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e6+5; 4 char s[maxn],t[maxn]; 5 int cnt[maxn][2]; 6 int n,k,tmp; 7 void work(char st[]) 8 { 9 memset(cnt,0,sizeof(cnt)); 10 cnt[0][0]=-1;tmp=0; 11 for(int i=1;i<=n;++i) 12 { 13 cnt[++tmp][0]=st[i]-‘0‘; 14 cnt[tmp][1] = cnt[tmp-1][0]==st[i]-‘0‘?cnt[tmp-1][1]+1:1; 15 if(cnt[tmp][1]==k) tmp-=k; 16 } 17 for(int i=1;i<=n;++i) {if(i<=tmp) st[i]=cnt[i][0]+‘0‘;else st[i]=‘0‘;} 18 } 19 int main() 20 { 21 scanf("%d%d",&n,&k); 22 scanf("%s",s+1); 23 scanf("%s",t+1); 24 work(s);work(t); 25 for(int i=1;i<=n;++i) {if(s[i]!=t[i]) {puts("No");return 0;}} 26 puts("Yes"); 27 return 0; 28 }
F - Frank
Unsolved.
G - Pyramid
题解:打表找规律,ans=n(n+1)(n+2)(n+3).
参考代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int mod=1e9+7; 5 LL quick_pow(LL a,LL b) 6 { 7 LL ans=1; 8 while(b) 9 { 10 if(b&1) ans=ans*a%mod; 11 a=a*a%mod; 12 b>>=1; 13 } 14 return ans; 15 } 16 int main() 17 { 18 int t; 19 scanf("%d",&t); 20 int l24=quick_pow(24,mod-2); 21 while(t--) 22 { 23 int n; 24 scanf("%d",&n); 25 LL ans=1; 26 ans=ans*n%mod; 27 ans=ans*(n+1)%mod; 28 ans=ans*(n+2)%mod; 29 ans=ans*(n+3)%mod; 30 ans=ans*l24%mod; 31 printf("%lld ",ans); 32 } 33 }
H - Huge Discount
Unsolved.
I - Magic Potion
队友写的,好像是最大流,题解待更。
参考代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1010; 4 const int maxm=1e5+5; 5 const int inf=0x3f3f3f3f; 6 struct Edge{ 7 int to,nxt,cap,flow; 8 }edge[maxm]; 9 int tol; 10 int head[maxn]; 11 void init(){ 12 tol=2; 13 memset(head,-1,sizeof(head)); 14 } 15 void AddEdge(int u,int v,int w,int rw=0){ 16 edge[tol].to=v;edge[tol].cap=w;edge[tol].flow=0; 17 edge[tol].nxt=head[u];head[u]=tol++; 18 edge[tol].to=u;edge[tol].cap=rw;edge[tol].flow=0; 19 edge[tol].nxt=head[v];head[v]=tol++; 20 } 21 int Q[maxn]; 22 int dep[maxn],cur[maxn],sta[maxn]; 23 bool bfs(int s,int t,int n){ 24 int front=0,tail=0; 25 memset(dep,-1,sizeof(dep[0])*(n+1)); 26 dep[s]=0; 27 Q[tail++]=s; 28 while(front<tail){ 29 int u=Q[front++]; 30 for(int i=head[u];i!=-1;i=edge[i].nxt){ 31 int v=edge[i].to; 32 if(edge[i].cap>edge[i].flow&&dep[v]==-1){ 33 dep[v]=dep[u]+1; 34 if(v==t) return true; 35 Q[tail++]=v; 36 } 37 } 38 } 39 return false; 40 } 41 int dinic(int s,int t,int n){ 42 int maxflow=0; 43 while(bfs(s,t,n)){ 44 for(int i=0;i<n;i++) cur[i]=head[i]; 45 int u=s,tail=0; 46 while(cur[s]!=-1){ 47 if(u==t){ 48 int tp=inf; 49 for(int i=tail-1;i>=0;i--) 50 { 51 tp=min(tp,edge[sta[i]].cap-edge[sta[i]].flow); 52 } 53 maxflow+=tp; 54 for(int i=tail-1;i>=0;i--){ 55 edge[sta[i]].flow+=tp; 56 edge[sta[i]^1].flow-=tp; 57 if(edge[sta[i]].cap-edge[sta[i]].flow==0) tail=i; 58 } 59 u=edge[sta[tail]^1].to; 60 } 61 else if(cur[u]!=-1&&edge[cur[u]].cap>edge[cur[u]].flow&&dep[u]+1==dep[edge[cur[u]].to]){ 62 sta[tail++]=cur[u]; 63 u=edge[cur[u]].to; 64 } 65 else{ 66 while(u!=s&&cur[u]==-1) u=edge[sta[--tail]^1].to; 67 cur[u] = edge [cur[u]].nxt; 68 } 69 } 70 } 71 return maxflow; 72 } 73 int main() 74 { 75 init(); 76 int n,m,k; 77 scanf("%d%d%d",&n,&m,&k); 78 int ti,mi; 79 int ss=0,t=n+m+5; 80 int s1=1,s2=2; 81 for(int i=1;i<=n;i++) AddEdge(s1,i+2,1); 82 for(int i=1;i<=n;i++) AddEdge(s2,i+2,1); 83 AddEdge(ss,s1,n); 84 AddEdge(ss,s2,k); 85 for(int i=1;i<=n;i++) 86 { 87 scanf("%d",&ti); 88 for(int j=1;j<=ti;j++) 89 { 90 scanf("%d",&mi); 91 AddEdge(i+2,n+2+mi,1); 92 } 93 } 94 for(int i=1;i<=m;i++) 95 { 96 AddEdge(i+n+2,t,1); 97 } 98 int ans=dinic(ss,t,t+1); 99 printf("%d ",ans); 100 } 101
J - Prime Game
队友写的,题解待更。
参考代码:
1 #include<bits/stdc++.h> 2 #define maxl 1000010 3 using namespace std; 4 5 int n; 6 int a[maxl],p[maxl],dy[maxl]; 7 long long v[maxl]; 8 bool no[maxl]; 9 vector <int> f[maxl]; 10 long long ans; 11 12 inline void shai() 13 { 14 no[1]=true; 15 int t,j; 16 for(int i=2;i<maxl;i++) 17 { 18 if(!no[i]) p[++p[0]]=i,dy[i]=i; 19 j=1,t=i*p[1]; 20 while(j<=p[0] && t<maxl) 21 { 22 dy[t]=p[j]; 23 no[t]=true; 24 if(i%p[j]==0) 25 break; 26 t=i*p[++j]; 27 } 28 } 29 } 30 31 inline void prework() 32 { 33 for(int i=1;i<=p[0];i++) 34 f[p[i]].clear(); 35 for(int i=1;i<=n;i++) 36 { 37 scanf("%d",&a[i]); 38 int x=a[i],last=0; 39 while(x>1) 40 { 41 if(dy[x]!=last) 42 f[dy[x]].push_back(i); 43 last=dy[x]; 44 x/=dy[x]; 45 } 46 } 47 } 48 49 inline void mainwork() 50 { 51 ans=0;int l,r,len; 52 long long tmp; 53 for(int i=1;i<=p[0];i++) 54 if(f[p[i]].size()>0) 55 { 56 tmp=v[n]; 57 l=1;r=0;len=f[p[i]].size(); 58 if(f[p[i]][0]>1) 59 tmp-=v[f[p[i]][0]-1]; 60 for(int j=0;j<len-1;j++) 61 if(f[p[i]][j+1]>f[p[i]][j]+1) 62 { 63 l=f[p[i]][j]+1;r=f[p[i]][j+1]-1; 64 tmp-=v[r-l+1]; 65 } 66 if(f[p[i]][len-1]<n) 67 tmp-=v[n-f[p[i]][len-1]]; 68 ans+=tmp; 69 } 70 } 71 72 inline void print() 73 { 74 printf("%lld ",ans); 75 } 76 77 int main() 78 { 79 shai(); 80 for(long long i=1;i<maxl;i++) 81 v[i]=i*(i+1)/2; 82 while(~scanf("%d",&n)) 83 { 84 prework(); 85 mainwork(); 86 print(); 87 } 88 return 0; 89 }
K - Kangaroo Puzzle
随机化。。
1 #include<bits/stdc++.h> 2 using namespace std; 3 char s[25][25]; 4 int n,m; 5 int main() 6 { 7 scanf("%d%d",&n,&m); 8 for(int i=1;i<=n;++i) scanf("%s",s[i]); 9 srand(time(0)); 10 char str[4]={‘L‘,‘R‘,‘U‘,‘D‘}; 11 for(int i=1;i<=20;++i)printf("U"); 12 for(int i=1;i<=20;++i)printf("R"); 13 for(int i=1;i<=20;++i)printf("D");///////adsfag 14 for(int i=1;i<=20;++i)printf("L"); 15 for(int i=1;i<=49920;++i) 16 { 17 int x=rand()%4; 18 printf("%c",str[x]); 19 } 20 puts(""); 21 return 0; 22 }
L - Lagrange the Chef
Unsolved.
M - Mediocre String Problem
题解:给你两个字符串。让你从s1中取l,r一个子串,s2的前缀,把s2的前缀放到s1的后面,组成一个回文串,问你you多少种组合方式。
我们可以把它转化为选l,x,r 和f使得l~x和1~f对称,把s1翻转,用exkmp处理,x~r为回文串.然后我们可以枚举r,用Manacher处理s1,把exnext反转,然后记录前缀和.
即可。
参考代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 #define pii pair<int,int> 5 const int INF=0x3f3f3f3f; 6 const int maxn=1e6+10; 7 char s[maxn],t[maxn]; 8 int lens,lent; 9 int mynext[maxn],extend[maxn]; 10 ll sum[maxn]; 11 12 void pre_exkmp(char x[],int m,int nxt[]) 13 { 14 nxt[0]=m; 15 int j=0; 16 while(j+1<m && x[j]==x[j+1]) j++; 17 nxt[1]=j; 18 int k=1; 19 for(int i=2;i<m;++i) 20 { 21 int p=nxt[k]+k-1; 22 int L=nxt[i-k]; 23 if(i+L<p+1) nxt[i]=L; 24 else 25 { 26 j=max(0,p-i+1); 27 while(i+j<m&&x[i+j]==x[j]) j++; 28 nxt[i]=j; 29 k=i; 30 } 31 } 32 } 33 void exkmp(char x[],int m,char y[],int n,int nxt[],int extend[]) 34 { 35 pre_exkmp(x,m,nxt); 36 int j=0; 37 while(j<n && j<m&& x[j]==y[j]) ++j; 38 extend[0]=j; 39 int k=0; 40 for(int i=1;i<n;++i) 41 { 42 int p=extend[k]+k-1; 43 int L=nxt[i-k]; 44 if(i+L<p+1) extend[i]=L; 45 else 46 { 47 j=max(0,p-i+1); 48 while(i+j<n&&j<m&&y[i+j]==x[j]) ++j; 49 extend[i]=j; 50 k=i; 51 } 52 } 53 } 54 char Ma[maxn<<2]; 55 int len[maxn<<1]; 56 void Manacher(char s[],int le) 57 { 58 int l=0; 59 Ma[l++]=‘$‘; Ma[l++]=‘#‘; 60 for(int i=0;i<le;++i) Ma[l++]=s[i],Ma[l++]=‘#‘; 61 Ma[l]=0; 62 int mx=0,id=0; 63 for(int i=0;i<l;++i) 64 { 65 len[i]=mx>i?min(len[2*id-i],mx-i):1; 66 while(Ma[i+len[i]]==Ma[i-len[i]]) len[i]++; 67 if(i+len[i]>mx) mx=i+len[i],id=i; 68 } 69 } 70 //moban 71 72 ll getsum(int l,int r) 73 { 74 if(l>r) return 0; 75 else if(l<=0) return sum[r]; 76 else return sum[r]-sum[l-1]; 77 } 78 79 int main() 80 { 81 scanf("%s%s",s,t); 82 lens=strlen(s);lent=strlen(t); 83 Manacher(s,lens);//len[] 84 reverse(s,s+lens); 85 exkmp(t,lent,s,lens,mynext,extend); 86 reverse(extend,extend+lens); 87 sum[0]=extend[0]; 88 for(int i=1;i<lens;++i) sum[i]=sum[i-1]+extend[i]; 89 ll ans=0; 90 for(int i=2;i<2*lens+3;++i) 91 { 92 int cnt=len[i]-1; 93 if(cnt==0 || len[i]==0) continue; 94 if(cnt&1) 95 { 96 int w=(i-2)/2; 97 int r=w-1; 98 int l=w-len[i]/2; 99 ans+=getsum(l,r); 100 } 101 else 102 { 103 int w=(i-2-1)/2; 104 int r=w-1; 105 int l=w-cnt/2; 106 ans+=getsum(l,r); 107 } 108 } 109 printf("%lld ",ans); 110 111 return 0; 112 }
以上是关于2018 ACM-ICPC南京区域赛题解的主要内容,如果未能解决你的问题,请参考以下文章
2013 ACM-ICPC亚洲区域赛南京站C题 题解 轮廓线DP
2018ACM-ICPC亚洲区域赛南京站I题Magic Potion(网络流)
[计蒜客] ACM-ICPC 2018 南京赛区网络预赛 | 部分题解 | 线段树 + 线性筛 + 最短路