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

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

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

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

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

AC代码如下:

#include
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
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
#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<0) b[i]=(b[i]-cbn(x+y-1,x-1)+mod)%mod;
		//cout<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<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
#define N 100009
using 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.x1; i>>=1){
		b[k].x++;
		if (i&1) flag=1;
	}
	b[k].y=flag;
}
matrix solve(int l,int r,int dep){
	//cout<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<>1]+1;
	for (i=1; i<=n; i++){
		scanf("%d",&a[i]); calc(i);
		//cout<


by lych

2017.9.25

你可能感兴趣的:(atcoder,比赛)