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;
}

原文地址:https://www.cnblogs.com/yuanquming/p/11609878.html

时间: 2024-08-30 17:30:40

CODE FESTIVAL 2017 qual A 题解的相关文章

CODE FESTIVAL 2017 qual A C Palindromic Matrix(思维题)

题目链接:点我呀 题意:给出n*m由26位小写字母组成的矩阵,问是否能够重构形成一个每行每列都是回文的矩阵 题解:分三种情况考虑(偶偶,奇奇,奇偶),每种情况下考虑最少 需要4个相同字母的字母数,2个相同字母的字母数和一个字母的字母数(只有奇奇的时候才需要一个字母) 最后判断一下.感觉自己的这个代码不是很简洁,明天起来看看别人怎么写的,睡觉去... 1 //Atcoder 3 2 #include <cstring> 3 #include <iostream> 4 #include

CODE FESTIVAL 2017 qual C F

以上为官方题解..

【Atcoder】CODE FESTIVAL 2017 qual C D - Yet Another Palindrome Partitioning

[题意] 给定只含小写字母的字符串,要求分割成若干段使段内字母重组顺序后能得到回文串,求最少分割段数.n<=2*10^5 [题解] 关键在于快速判断一个字符子串是否合法,容易发现合法仅当不存在或只存在一个奇数字符,其余字符均为偶数. 当涉及到奇偶性(%2)时,很自然能想到异或. 将小写字母a~z转化2^0~2^25,那么一个字符子串合法当且仅当其连续异或值是0或2^i(0<=i<=25). 令f[i]表示前i个合法的最少段数,sum[i]表示异或前缀和,则有: f[i]=min(f[j]

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

题目大意:给你\(A\)个a,\(B\)个b,\(C\)个c,要你构造一个字符串,使它的最小循环表示法最大.求这个表示法.解题思路:不知道怎么证,但把a.b.c当做单独的字符串扔进容器,每次把字典序最小的和字典序最大的两个字符串合并就是答案.容器用multiset即可. C++ Code: #include<cstdio> #include<set> #include<string> using namespace std; multiset<string>

101 to 010 Atcoder CODE FESTIVAL 2017 qual B D

https://www.luogu.org/problemnew/show/AT3575 题解 根本不会.. 错误记录:缺少32行的转移.显然这个转移是必要的 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 using namespace std; 6 #define fi first 7 #define se second 8 #define

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

个人心得:其实本来这题是有规律的不过当时已经将整个模拟过程都构思出来了,就打算试试,将每个字符和总和用优先队列 装起来,然后枚举每个点,同时进行位置标志,此时需要多少个点的时候拿出最大的和出来,若不满足就输出No,结果一直卡在三组 数据.比赛完后一想,优先队列虽然用处大,不过当行列存在奇数的时候此时只要2个就可以,而如果你从最大的4个中拿出来, 那么下一层循环中必然有一个位置无法填充,如此就导致了算法的失败.所以后面建立个奇偶判定就好了. 感悟: 多注意思考和细节,从不同的层次看待问题,既可以全

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

个人心得:开始拿着题目还是有点懵逼的,以前做过相同的,不过那是按一个位置行列全都反之,当时也是没有深究.现在在打比赛不得不 重新构思,后面一想把所有的状态都找出来,因为每次确定了已经按下的行和列后,按不同的操作所加的数都是一样的,于是就想到了用set 暴力枚举,从1-n个分别行列按钮,然后再枚举不同操作即确定行时再对列进行操作,每次操作放入set就可以了. 题目: Problem Statement We have a grid with N rows and M columns of squa

atcoder CODE FESTIVAL 2017 qual C D - Yet Another Palindrome Partitioning

Problem Statement We have a string s consisting of lowercase English letters. Snuke is partitioning s into some number of non-empty substrings. Let the subtrings obtained be s1, s2, …, sNfrom left to right. (Here, s=s1+s2+…+sN holds.) Snuke wants to

【AtCoder】CODE FESTIVAL 2017 qual C

A - Can you get AC? No #include <bits/stdc++.h> #define fi first #define se second #define pii pair<int,int> #define pb push_back #define mp make_pair using namespace std; typedef long long int64; char s[15]; int main() { scanf("%s",