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

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

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

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

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

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

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

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

 

以上是关于2018 ACM-ICPC南京区域赛题解的主要内容,如果未能解决你的问题,请参考以下文章

2013 ACM-ICPC亚洲区域赛南京站C题 题解 轮廓线DP

2018ACM-ICPC亚洲区域赛南京站I题Magic Potion(网络流)

ACM-ICPC 2018 南京网络赛

[计蒜客] ACM-ICPC 2018 南京赛区网络预赛 | 部分题解 | 线段树 + 线性筛 + 最短路

2018.11.25 齐鲁工业大学ACM-ICPC迎新赛正式赛题解

南京网络赛题解 2018