CODE FESTIVAL 2017 qual A 题解

传送门

(A)

咕咕

const int N=25;
const char t[]={" YAKI"};
char s[N];int n;
int main(){
	scanf("%s",s+1),n=strlen(s+1);
	if(n<4)return puts("No"),0;
	fp(i,1,4)if(s[i]!=t[i])return puts("No"),0;
	puts("Yes");
	return 0;
}

(B)

如果翻转了(i)(j)列,那么变黑的格子个数就是(i imes m+j imes n-2 imes i imes j),那么枚举行数和列数就行了

int n,m,k;
int main(){
	scanf("%d%d%d",&n,&m,&k);
	fp(i,0,n)fp(j,0,m)if(k==i*m+j*n-(i*j<<1))return puts("Yes"),0;
	puts("No");
	return 0;
}

(C)

先把行数或列数为奇数时中间多出来的那一行一列去掉,那么一个格子((i,j))必须和其它三个格子相等,记录一下这种四个一相等的次数,以及行列为奇数时中间多出来的那一行中的两个一相等的次数,判断一下是否合法即可

//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=105;
char s[N];int c[26],c1,c2,n,m;
inline int min(R int x,R int y){return x<y?x:y;}
int main(){
	scanf("%d%d",&n,&m);
	fp(i,1,n){
		scanf("%s",s+1);
		fp(j,1,m)++c[s[j]-'a'];
	}
	c1=(n>>1)*(m>>1),c2=(n&1)*(m>>1)+(m&1)*(n>>1);
	for(R int k,i=0;c1&&i<26;++i){
		k=min(c1,c[i]>>2);
		c1-=k,c[i]-=(k<<2);
	}
	if(c1)return puts("No"),0;
	for(R int k,i=0;c2&&i<26;++i){
		k=min(c2,c[i]>>1);
		c2-=k,c[i]-=(k<<1);
	}
//	printf("%d %d
",c1,c2);
	if(c2)return puts("No"),0;
	puts("Yes");
	return 0;
}

(D)

脑子估计生锈了……

首先把曼哈顿距离转切比雪夫距离,即把((i,j))变成((i+j,i-j)),然后我们发现在新图上,一个点到所有与它切比雪夫距离为(d)的点必定有横坐标或纵坐标之差为(d),那么我们按(d imes d)把所有的点分组,每组相同颜色,且与它周围八个相邻的组颜色都不同,这样可以发现必定合法

然后要每组和周围相邻八组颜色都不同,只要奇数行填(12121212...),偶数行填(343434...)就好了

//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=505;
const char c[]={"RYGB"};
char mp[N][N];int n,m,d;
int main(){
	scanf("%d%d%d",&n,&m,&d);
	fp(i,1,n)fp(j,1,m){
		R int x=i+j,y=i-j+m-1;
		mp[i][j]=c[((y/d)&1)+((x/d)&1)*2];
	}
	fp(i,1,n){
		fp(j,1,m)putchar(mp[i][j]);
		putchar('
');
	}
	return 0;
}

(E)

首先第一次肯定是整行或整列的,那么我们假设第一次是整列,并假设整列涂色的区间为([l,r])(其中(l,r)两列必须可以涂色),设这个区间中上下都可以涂色的列的个数为(k),那么这一部分的贡献就是(2^k)

然后考虑两边,我们强制两边都得先横着涂一次,之后随意。以左边为例,记这一部分朝下的有(y)个人,朝上的有(z)个人,朝右的有(x)个人,如果把横的视为蓝色,纵的视为红色,那么把一个最终的方案的轮廓线给画出来再把后一部分取反,就是从((0,0))走到(O(x,y+z))的方案数({x+y+zover x}),且鉴于横的必须有一个涂满,所以走了(x-1)次右之后必须向下,所以最终的方案数为({x+y+zover x}-{x+y+z-1over x}={x+y+z-1over x-1})。然后把前后缀和分别搞出来就行了

//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int P=998244353;
inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
	R int res=1;
	for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
	return res;
}
const int N=2e5+5,M=1e6+5;
int fac[M],ifac[M],bin[M],ibin[M];
inline int C(R int n,R int m){return m>n?0:1ll*fac[n]*ifac[m]%P*ifac[n-m]%P;}
void init(int n=1e6){
	fac[0]=ifac[0]=bin[0]=ibin[0]=1;
	fp(i,1,n)fac[i]=mul(fac[i-1],i);
	ifac[n]=ksm(fac[n],P-2);
	fd(i,n-1,1)ifac[i]=mul(ifac[i+1],i+1);
	fp(i,1,n)bin[i]=mul(bin[i-1],2);
	fp(i,1,n)ibin[i]=mul(ibin[i-1],499122177);
}
char mp[4][N];int sum[4][N],f[N],b[N],s[N];
int n,m,res;
void calc(){
	memset(f,0,sizeof(f));
	memset(b,0,sizeof(b));
	memset(s,0,sizeof(s));
	R int x=sum[0][n],y,z;
	fp(i,0,m){
		if(mp[2][i+1]=='0'&&mp[3][i+1]=='0')continue;
		y=sum[2][i],z=sum[3][i];
		f[i]=(x?C(x+y+z-1,x-1):(!y&&!z));
	}
	x=sum[1][n];
	fd(i,m+1,1){
		if(mp[2][i-1]=='0'&&mp[3][i-1]=='0')continue;
		y=sum[2][m]-sum[2][i-1],z=sum[3][m]-sum[3][i-1];
		b[i]=(x?C(x+y+z-1,x-1):(!y&&!z));
	}
	fp(i,1,m)s[i]=s[i-1]+(mp[2][i]=='1'&&mp[3][i]=='1');
	fp(i,0,m)f[i]=mul(f[i],ibin[s[i]]);
	fd(i,m+1,1)b[i]=add(b[i+1],mul(b[i],bin[s[i-1]]));
	fp(i,1,m)upd(res,mul(f[i-1],b[i+1]));
}
int main(){
//	freopen("testdata.in","r",stdin);
	init();
	scanf("%d%d",&n,&m);
	fp(i,0,3)scanf("%s",mp[i]+1);
	fp(i,0,3){
		R int t=(i<=1?n:m);
		fp(j,1,t)sum[i][j]=sum[i][j-1]+(mp[i][j]=='1');
	}
	if(!sum[0][n]&&!sum[1][n]&&!sum[2][m]&&!sum[3][m])return puts("1"),0;
	calc();
	swap(mp[0],mp[2]),swap(mp[1],mp[3]);
	swap(sum[0],sum[2]),swap(sum[1],sum[3]);
	swap(n,m);
	calc();
	printf("%d
",res);
	return 0;
}

(F)

首先如果每个数分别考虑,那么上界肯定是(log a_i)

不过有的操作之间可以合并,一个数是(2)的幂次那么所有操作经过它都没关系,否则每一次操作必定只能是往左或者往右

然后贪心,从左往右,记录前面给了后面多少,多余的一次能往前就往前

//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=1e5+5;
int a[N],b[N],c[N],n,res,lst,tmp;
int main(){
	scanf("%d",&n);
	for(R int i=1,x;i<=n;++i){
		scanf("%d",&x),a[i]=x,b[i]=-1;
		while(a[i])++b[i],a[i]>>=1;
		c[i]=((x&-x)!=x),res+=b[i]+c[i];
	}
	fp(i,1,n){
		tmp=min(lst,b[i]),res-=tmp,lst-=tmp;
		if(lst&&c[i])--res,--c[i];
		lst=b[i]+c[i];
	}
	printf("%d
",res);
	return 0;
}
原文地址:https://www.cnblogs.com/yuanquming/p/11609878.html