atcoder CODE FESTIVAL 2017 qual A 手速(雾)赛

来源:互联网 发布:家庭对性格的影响 知乎 编辑:程序博客网 时间:2024/06/18 20:49

       这个比赛看起来好像挺重要的,,(结果来了一众大佬谁都打不过qaq)

       A,B题不知道是干什么的

       C题(其实也是不知道在干什么)就是给一个字母矩阵,重排列后问是否能使它水平轴对称+竖直轴对称。

       可以发现一个矩阵最多由三部分组成:1.中心点,需要1个字母;2.中轴线,需要2个相同字母为1对填上去;3.其余部分,需要4个相同字母为1组填上去。显然能填3就能填2,能填2就能填1,因此考虑从3->2->1贪心放即可。

AC代码如下:

#include<bits/stdc++.h>using namespace std; int m,n,num[26]; char s[100009];int main(){scanf("%d%d",&m,&n);int s1=(m>>1)*(n>>1),s2=(m&1)*(n>>1)+(m>>1)*(n&1),s3=m&n&1;int i,j;for (i=1; i<=m; i++){scanf("%s",s+1);for (j=1; j<=n; j++) num[s[j]-'a']++;}for (i=0; i<26; i++){while (num[i]>=4 && s1){ num[i]-=4; s1--; }while (num[i]>=2 && s2){ num[i]-=2; s2--; }while (num[i] && s3){ num[i]--; s3--; }if (num[i]) break;}puts(i<26?"No":"Yes");return 0;}

          从D题开始才开始有含金量的题目,,(可能F题也不那么难?),,然后我开场开了D题,看错输出格式爆了2发oj,,,啊难受

       题意就是给你m,n,d,要求构造一个染4色的方案,使得曼哈顿距离恰好为d的任何一对点颜色不同。

       首先考虑x+y->x,x-y->y,这样就变成了以(x,y)为中心,边心距为d的正方形的轮廓不能喝(x,y)同色。考虑x所在的行,我们可以采用先d个为一段,换一种颜色再d个为一段,再换回原来的颜色d个一段的方式染。这样可以推广到2维,考虑以一个d*d的正方形为一个单位,然后每4个的颜色两两不同,可以发现满足条件。

AC代码如下:

#include<bits/stdc++.h>using namespace std; char ch[2][2]={{'R','B'},{'G','Y'}}; int n,m,k;char calc(int x,int y){int a=x+y,b=x-y;a+=2000; b+=2000;a/=k; b/=k; a&=1; b&=1;return ch[a][b];}int main(){scanf("%d%d%d",&m,&n,&k);int i,j;for (i=1; i<=m; i++){for (j=1; j<=n; j++) printf("%c",calc(i,j)); puts("");}return 0;}

          E题应该是唯一有一点难度的题目?,反正我可能是做了挺久的。

       E题题意为给你一个m*n的矩形,在矩形的四周有若干个人,每个人会向对面一直走,知道走到一个被染色的方格。然后在走的过程中他会把脚下的格子染成他自己的颜色。每个人颜色不同。求最后矩形的样子有几种。

       首先分上下/左右先走两种情况。考虑上下先走,那么会把矩形分成左右两边。并且可以发现如果最早走的是上下中的第x个和第y个,那么x~y中间的就不能被左右的人走到了。所以可以考虑最早走的是第x~y个,然后左右的人再走。

      如果令f[i]表示走了i+1左边的方案数,g[i]表示走了i-1右边的方案数,那么答案就是Σf[i]*g[j]*2^(s[j]-1-s[i])=Σ(f[i]/2^s[i])*(g[j]*2^s[j-1]),其中s[i]表示1~i中有几个是上下都有人的。因此关键是求出f[i],同样考虑左边的先走的是a~b,那么答案就是C(a+c,a)*C(b+d,b),其中c,d表示前i列中上、下个有多少人。考虑C(a+c,a)表示的是用(0,0)走到(a,c)的方案书,那么可以发现答案等价于从(0,0)走到(c+d,t),并且在第c列必须走至少一步向上的方案数,其中t表示左边有几个人。所以答案就是C(c+d+t,t)-C(c+d-1+t,t)。

       最后小心特判全0的情况

AC代码如下:

#include<bits/stdc++.h>#define N 400009#define ll long long#define mod 998244353#define cbn(x,y) ((ll)fac[x]*inv[y]%mod*inv[(x)-(y)]%mod)using namespace std; int m,n,a[N],b[N],fac[N],inv[N]; char A[N],B[N],C[N],D[N];int solve(int m,int n,char *A,char *B,char *C,char *D){int i,x,y;memset(a,0,sizeof(a)); memset(b,0,sizeof(b));a[0]=b[n+1]=1;for (i=1,y=0; i<=m; i++) if (A[i]=='1') y++;for (i=1,x=0; i<=n; i++){if (C[i]=='1') x++;if (D[i]=='1') x++;a[i]=cbn(x+y,x);if (x) a[i]=(a[i]-cbn(x+y-1,x-1)+mod)%mod;//cout<<i<<' '<<a[i]<<endl;}for (i=1,y=0; i<=m; i++) if (B[i]=='1') y++;for (i=n,x=0; i; i--){if (C[i]=='1') x++;if (D[i]=='1') x++;b[i]=cbn(x+y,x);if (x>0) b[i]=(b[i]-cbn(x+y-1,x-1)+mod)%mod;//cout<<i<<' '<<b[i]<<endl;}int tmp;for (i=0,tmp=1; i<=n; i++){if (i>0 && C[i]=='1' && D[i]=='1') tmp=(ll)tmp*(mod+1>>1)%mod;a[i]=(ll)a[i]*tmp%mod;if (i<=n && C[i+1]=='0' && D[i+1]=='0') a[i]=0;}for (i=1; i<=n; i++) a[i]=(a[i]+a[i-1])%mod;for (i=tmp=1; i<=n+1; i++){b[i]=(ll)b[i]*tmp%mod;if (i<=n && C[i]=='1' && D[i]=='1') tmp=tmp*2%mod;if (i>1 && C[i-1]=='0' && D[i-1]=='0') b[i]=0;}int ans=0;for (i=1; i<=n; i++) ans=(ans+(ll)b[i+1]*a[i-1])%mod;//cout<<ans<<endl;return ans;}int main(){scanf("%d%d",&m,&n);scanf("%s%s%s%s",A+1,B+1,C+1,D+1);int i;for (i=1; i<=m; i++) if (A[i]=='1' || B[i]=='1') break;if (i>m){for (i=1; i<=n; i++) if (C[i]=='1' || D[i]=='1') break;if (i>n){ puts("1"); return 0; }}fac[0]=inv[0]=inv[1]=1;for (i=1; i<=(m+n<<1); i++) fac[i]=(ll)fac[i-1]*i%mod;for (i=2; i<=(m+n<<1); i++) inv[i]=mod-(ll)inv[mod%i]*(mod/i)%mod;for (i=2; i<=(m+n<<1); i++) inv[i]=(ll)inv[i-1]*inv[i]%mod;printf("%d\n",(solve(m,n,A,B,C,D)+solve(n,m,C,D,A,B))%mod);return 0;}

            最后的F题似乎比E题简单多了。。我A掉E发现F已经过了一片了,qaq

        F就是已知一个若干个1构成的序列,然后每次可以选择2n个连续的数,按照(1,2)(3,4),...(2n-1,2n)的方式合并,得到最终的序列。现在告诉你最终的序列,求最少几步。

        显然应该倒过来做。那么考虑一次操作就是把连续的若干>1的数拆成两半,显然应该贪心地拆成均匀的两份。那么考虑拆x的过程中,每一步之后都是由两部分组成,一部分都是t,另一部分都是t+1。

        然后考虑原问题。显然产生的1会将原问题分成两个子问题。显然最小的数最早产生1,那么把原问题分成两个问题之后递归地做。注意到最小的数产生1之后可能还有部分2,需要枚举放在左边还是右边。

AC代码如下:

#include<bits/stdc++.h>#define N 100009using namespace std; int n,a[N],lg2[N];struct node{ int x,y; }f[17][N],b[N];struct matrix{ int p[2][2]; };bool operator <(node u,node v){ return u.x<v.x; }int getmin(int x,int y){int k=lg2[y-x+1];//cout<<""<<x<<' '<<y<<endl;//cout<<k<<' '<<x<<' '<<y<<' '<<f[k][x].y<<' '<<f[k][y-(1<<k)+1].y<<endl;return min(f[k][x],f[k][y-(1<<k)+1]).y;}void calc(int k){int flag=0,i=a[k];for (; i>1; i>>=1){b[k].x++;if (i&1) flag=1;}b[k].y=flag;}matrix solve(int l,int r,int dep){//cout<<l<<' '<<r<<endl;if (l>r){matrix x;x.p[0][0]=0; x.p[0][1]=x.p[1][0]=x.p[1][1]=1;return x;}int mid=getmin(l,r),i,j,k,x=b[mid].x,y=b[mid].y;matrix u=solve(l,mid-1,x),v=solve(mid+1,r,x),z;for (i=0; i<2; i++)for (j=0; j<2; j++){z.p[i][j]=1000000000;for (k=0; k<=y; k++) z.p[i][j]=min(z.p[i][j],u.p[i][k]+v.p[y-k][j]);}//cout<<l<<' '<<r<<' '<<mid<<' '<<x<<' '<<dep<<endl;for (i=0; i<2; i++)for (j=0; j<2; j++) z.p[i][j]+=x-dep;if (dep<x)for (i=0; i<2; i++)for (j=0; j<2; j++) z.p[i][j]=z.p[0][0];//for (i=0; i<2; i++)//for (j=0; j<2; j++) cout<<z.p[i][j]<<' ';puts("");return z;}int main(){scanf("%d",&n);int i,j;for (i=2; i<=n; i++) lg2[i]=lg2[i>>1]+1;for (i=1; i<=n; i++){scanf("%d",&a[i]); calc(i);//cout<<i<<' '<<b[i].x<<' '<<b[i].y<<endl;}for (i=1; i<=n; i++) f[0][i]=(node){a[i],i};for (i=1; i<=16; i++)for (j=1; j<=n; j++){f[i][j]=f[i-1][j];if (j+(1<<i-1)<=n) f[i][j]=min(f[i][j],f[i-1][j+(1<<i-1)]);}printf("%d\n",solve(1,n,0).p[0][0]);return 0;}


by lych

2017.9.25

原创粉丝点击