AtCoder Grand Contest 017
noi前橙名计划失败。全程搞C而gg……
A - Biscuits
题意:背包,求价值为奇/偶的方案数。
#include<cstdio> #include<queue> #include<algorithm> #define ld long double #define MN 21000000 using namespace std; int read_p,read_ca; inline int read(){ read_p=0;read_ca=getchar(); while(read_ca<'0'||read_ca>'9') read_ca=getchar(); while(read_ca>='0'&&read_ca<='9') read_p=read_p*10+read_ca-48,read_ca=getchar(); return read_p; } int n,p,a; long long mmh[2]; int main(){ mmh[0]=1; n=read();p=read(); while(n--){ a=read()&1; if (a&1){ mmh[0]=mmh[1]=mmh[1]+mmh[0]; }else mmh[0]<<=1,mmh[1]<<=1; } printf("%lld\n",mmh[p]); }
B - Moderate Differences
题意:询问是否可以把B-A表示成n-1个绝对值在C和D之间的数的和。
#include<cstdio> #include<queue> #include<algorithm> #define ld long double #define MN 21000000 using namespace std; int read_p,read_ca; inline int read(){ read_p=0;read_ca=getchar(); while(read_ca<'0'||read_ca>'9') read_ca=getchar(); while(read_ca>='0'&&read_ca<='9') read_p=read_p*10+read_ca-48,read_ca=getchar(); return read_p; } long long n,a,b,c,d,w; int main(){ scanf("%lld%lld%lld%lld%lld",&n,&a,&b,&c,&d); b-=a;n--; for (int i=0;i<=n;i++){ w=-d*i+c*(n-i); if (b-w<=(d-c)*n&&b>=w) return /*printf("%d %lld %lld %lld\n",i,w,n,b-w),*/puts("YES"),0; } puts("NO"); }
C - Snuke and Spells
题意:定义一种操作为当序列长度为k时把所有等于k的元素删去,问将给定序列至少修改多少元素,序列能进行不断操作后为空。
题解:有一个结论:如果等于 $i$ 的数有$N_{i}$个,那么看成区间$[i-N_{i}+1,i]$,未被区间覆盖的位置数量即为答案。
#include<cstdio> #include<algorithm> #define MN 210000 using namespace std; int n,m,x,y,c[MN<<1],t[MN],a[MN],mmh=0; int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=n;i++){ scanf("%d",&a[i]); if (a[i]-t[a[i]]>0) mmh+=(c[a[i]-t[a[i]]]++)==0; t[a[i]]++; } while (m--){ scanf("%d%d",&x,&y); t[a[x]]--; if (a[x]-t[a[x]]>0)mmh-=(--c[a[x]-t[a[x]]])==0; a[x]=y; if (a[x]-t[a[x]]>0)mmh+=(c[a[x]-t[a[x]]]++)==0; t[a[x]]++; printf("%d\n",n-mmh); } }
D - Game on Tree
题意:裸删边游戏。
题解:大佬论文
#include<cstdio> #include<queue> #include<algorithm> #define ld long double #define MN 210000 using namespace std; int read_p,read_ca; inline int read(){ read_p=0;read_ca=getchar(); while(read_ca<'0'||read_ca>'9') read_ca=getchar(); while(read_ca>='0'&&read_ca<='9') read_p=read_p*10+read_ca-48,read_ca=getchar(); return read_p; } struct na{int y,ne;}b[MN]; int n,m,l[MN],num=0,x,y,s[MN]; inline void in(int x,int y){ b[++num].y=y;b[num].ne=l[x];l[x]=num; } void dfs(int x,int f){ int u=0;s[x]=0; for (int i=l[x];i;i=b[i].ne) if (b[i].y!=f){ dfs(b[i].y,x);u^=s[b[i].y]+1; } s[x]=u; /*for (int i=l[x];i;i=b[i].ne) if (b[i].y!=f){ if ((u^s[b[i].y])==0) s[x]=1; }*/ //printf("%d %d\n",x,s[x]); } int main(){ n=read(); for (int i=1;i<n;i++) x=read(),y=read(),in(x,y),in(y,x); dfs(1,0); puts(s[1]?"Alice":"Bob"); }
E - Jigsaw
题意:问能否把拼图排成一排使得相邻拼图契合。
题解:把拼图看成边,其两段信息作为点连边然后并查集。
#include<cstdio> #include<algorithm> #define NO return puts("NO"),0 using namespace std; int n,m,f[1000],a,b,c,d,x,y,D[1000],bo[1000],C[1000]; int gf(int x){return x==f[x]?x:f[x]=gf(f[x]);} int main(){ scanf("%d%d",&n,&m); for (int i=1;i<999;i++) f[i]=i; while (n--){ scanf("%d%d%d%d",&a,&b,&c,&d); if (c==0) x=a;else x=-c;x+=500; if (d==0) y=-b;else y=d;y+=500; f[gf(x)]=gf(y); D[x]++;D[y]--;bo[x]=1; } for (int i=1;i<500;i++) if (D[i]>0) NO; for (int i=501;i<999;i++) if (D[i]<0) NO; for (int i=1;i<999;i++) if (bo[gf(i)]|=bo[i],D[i]) C[f[i]]=1; for (int i=1;i<999;i++) if (f[i]==i&&!C[i]&&bo[i]) NO; puts("YES"); }
F - Zigzag
题意:在$\frac{n*(n+1)}{2}$三角形上从顶到底画m条可重合,不可相交的线,某些线的部分已经确定,求方案数,、
题解:dp[i][j]表示考虑了前$i$条线,第$i$条线的位置状态为$j$的方案数。转移起来有点麻烦,窝看并抄了dalao的代码,实现得非常优雅,大约是从高往低考虑往左走的线可以向往右的线转移。
#include<cstdio> #include<algorithm> #define MN 1000 using namespace std; const int MOD=1e9+7; int n,m,k,le[MN],ri[MN],x,y,z,mmh[1<<20],MMH=0; inline void M(int &x){while(x>=MOD)x-=MOD;} int lowbit(int x) { return x & -x; } int main(){ scanf("%d%d%d",&n,&m,&k);n--; for (int i=1;i<=m;i++) le[i]=(1<<n)-1,ri[i]=0; while(k--){ scanf("%d%d%d",&x,&y,&z);y--; if (z==0) le[x]^=1<<y;else ri[x]^=1<<y; } mmh[0]=1; for (int i=1;i<=m;i++){ for (int k=0;k<n;k++) for (int j=0;j<(1<<n);j++) if (~j>>k&1) M(mmh[j+(1<<k)-lowbit(j&~((1<<k)-1))]+=mmh[j]); for (int j=0;j<(1<<n);j++) if (!((j&ri[i])==ri[i]&&(j&le[i])==j)) mmh[j]=0; } for (int j=0;j<(1<<n);j++) M(MMH+=mmh[j]); printf("%d\n",MMH); }