CODE FESTIVAL 2017 qual A 题解

Posted yuanquming

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\times m+j\times n-2\times i\times 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\n",c1,c2);
    if(c2)return puts("No"),0;
    puts("Yes");
    return 0;

\(D\)

脑子估计生锈了……

首先把曼哈顿距离转切比雪夫距离,即把\((i,j)\)变成\((i+j,i-j)\),然后我们发现在新图上,一个点到所有与它切比雪夫距离为\(d\)的点必定有横坐标或纵坐标之差为\(d\),那么我们按\(d\times 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('\n');
    
    return 0;

\(E\)

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

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

以上是关于CODE FESTIVAL 2017 qual A 题解的主要内容,如果未能解决你的问题,请参考以下文章

java CODE FESTIVAL 2017 qual B问题A.

CODE FESTIVAL 2017 qual A--B-fLIP(换种想法,暴力枚举)

CODE FESTIVAL 2017 qual A--C - Palindromic Matrix(模拟所有情况,注意细节)

[Atcoder Code Festival 2017 Qual B Problem F]Largest Smallest Cyclic Shift

CODE FESTIVAL 2017 qual B C - 3 Steps

Atcoder Code Festival 2017 qual C 10.22 D题题解