NOIP2017提高组模拟赛 8(总结)
来源:互联网 发布:淘宝卖爱奇艺会员 编辑:程序博客网 时间:2024/05/22 06:35
NOIP2017提高组模拟赛 8(总结)
第一题 路径
一个定理,假如点i到点j有一条路径是偶数,那么其他路径也一定是偶数(最短距离需要的上下左右是固定的,多余的上和下抵消,多余的左和右抵消),反之亦然。
简单的证明,假如需要的是偶数,那么只需判断是否存在一个点到(0,0)的距离是偶数就行了(作为终点),其它点可以从(0,0)出发到(xi,yi)再回到(0,0),这样肯定为偶数步数。需要的是奇数的也类似。
#include<cstdio>#include<algorithm>#include<cmath>#define imax(a,b) ((a>b)?(a):(b))#define imin(a,b) ((a<b)?(a):(b))typedef long long ll;using namespace std;int ng,n,ne,a,b,s[5];int main(){ freopen("a.in","r",stdin); freopen("a.out","w",stdout); scanf("%d",&ng); while(ng--) { scanf("%d%d",&n,&ne); s[0]=s[1]=0; for(int i=1;i<=n;i++) { scanf("%d%d",&a,&b); int c=abs(a)+abs(b); s[c&1]++; } if(ne==0) { if(s[0]>0) printf("CAN\n"); else printf("CANNOT\n"); } else if(ne==1) { if(s[1]>0) printf("CAN\n"); else printf("CANNOT\n"); } } return 0;}
第二题 冠军
已知N一定是2的若干次幂,而且不超过16,也就是说N是{2,4,8,16}之中的某一个数。
现在的问题是:有多少种不同的分配方案,使得第i个选手能最终成为冠军?不妨假设该数值是ans[i]。
你的任务就是输出:ans[0]、ans[1]、….ans[N-1]。
一道状压DP题,不过要注意优化,过多的无用状态没过滤掉会被卡。
若beat[i][j]==’Y’ F[S][i]+=F[S1][i]*F[S-S1][j]
若beat[i][j]==’N’ F[S][j]+=F[S1][i]*F[S-S1][j]
F[S][i]表示选了S这几个拳手(2进制,0为不选,1为选),最终胜利的拳手为i的方案数。
结果会爆INT,要用LONG LONG来存。
(PS:一开始,码了搜索去找状态,结果WA了,机子单步不了,又找不出哪里错。后来比赛结束重新码了程序才过。)
#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#define imax(a,b) ((a>b)?(a):(b))#define imin(a,b) ((a<b)?(a):(b))#define pd(S,i) ((S&(1<<(i-1)))>0)typedef long long ll;using namespace std;const int MP=100500;int n,hn,nn,B[20],C[20];char st[20];bool ff[20][20];int Go[6][MP],Set[6][MP],one[MP],A[20];ll f[MP][20];int main(){ freopen("b.in","r",stdin); freopen("b.out","w",stdout); scanf("%d",&n); hn=n>>1; nn=(1<<n); for(int i=1;i<=n;i++) { scanf("%s",st); for(int j=1;j<=n;j++) ff[i][j]=(st[j-1]=='Y'); } one[0]=0; for(int i=1;i<nn;i++) one[i]=one[i>>1]+(i&1); for(int i=1;i<nn;i++) { if(one[i]==1) { Set[0][++Set[0][0]]=i; if(i<(1<<2)) Go[0][++Go[0][0]]=i; } else if(one[i]==2) { Set[1][++Set[1][0]]=i; if(i<(1<<4)) Go[1][++Go[1][0]]=i; } else if(one[i]==4) { Set[2][++Set[2][0]]=i; if(i<(1<<8)) Go[2][++Go[2][0]]=i; } else if(one[i]==8) { Set[3][++Set[3][0]]=i; if(i<(1<<16)) Go[3][++Go[3][0]]=i; } } for(int i=1;i<=Set[0][0];i++) { int S=Set[0][i]; for(int j=1;j<=n;j++) if(pd(S,j)) f[S][j]=1; } Set[4][0]=1; Set[4][1]=(1<<16)-1; int go=0; if(n==16) go=4; else if(n==8) go=3; else if(n==4) go=2; else go=1; for(int ho=1;ho<=go;ho++) { for(int i=1;i<=Set[ho][0];i++) { int S=Set[ho][i],S1; A[0]=0; for(int j=1;j<=n;j++) if(pd(S,j)) A[++A[0]]=j; for(int h=1;h<=Go[ho-1][0];h++) { int ss=Go[ho-1][h]; S1=0; B[0]=0; C[0]=0; for(int k=1;k<=(1<<ho);k++) { if(pd(ss,k)) { S1|=(1<<(A[k]-1)); B[++B[0]]=A[k]; } else C[++C[0]]=A[k]; } for(int fa=1;fa<=B[0];fa++) for(int fb=1;fb<=C[0];fb++) if(ff[B[fa]][C[fb]]) f[S][B[fa]]+=f[S1][B[fa]]*f[S-S1][C[fb]]; else f[S][C[fb]]+=f[S1][B[fa]]*f[S-S1][C[fb]]; } } } for(int i=1;i<=n;i++) printf("%I64d\n",f[nn-1][i]); return 0;}
第三题 指纹
这题比前一题好打多了,不过一直在调第二题,这题便没有做……
每一个指纹有四个参数ABCD
先考虑ABC,因为假设i的D很小,但ABC很大,那么它也会被刷掉。
按A排序,用B作为下标,存C。用线段树维护一段区间的最小值。
A从小到大排序,对于i来说,比它的A小的都已经加入了线段树中,若findmin(1,B)比C小,证明一定存在x的ABC均小于i,那么i也没有存在的意义了(打del标记)。
再考虑ABD,ACD,BCD,一共四种情况,逐一筛掉无用的指纹就行了。
#include<cstdio>#include<algorithm>#include<cmath>#define imax(a,b) ((a>b)?(a):(b))#define imin(a,b) ((a<b)?(a):(b))typedef long long ll;using namespace std;const int oo=1e9;const int N=1e5;struct data { int a,b,c,d,id; } d[N+100],dg[N+100];int n;bool ffg[N+100];int tree[N<<2];bool cmp(data A,data B) { return (A.a<B.a); }void build(int ro,int L,int R){ if(L==R) { tree[ro]=oo; return; } int Mid=(L+R)>>1; build(ro<<1,L,Mid); build(ro<<1|1,Mid+1,R); tree[ro]=imin(tree[ro<<1],tree[ro<<1|1]);}void pre(int ho){ for(int i=1;i<=n;i++) dg[i]=d[i]; if(ho==1) for(int i=1;i<=n;i++) swap(dg[i].c,dg[i].d); else if(ho==2) for(int i=1;i<=n;i++) swap(dg[i].b,dg[i].d); else if(ho==3) for(int i=1;i<=n;i++) swap(dg[i].a,dg[i].d); sort(dg+1,dg+1+n,cmp); build(1,1,n);}void updata(int ro,int L,int R,int x,int val){ if(L>x || R<x) return; if(L==x && x==R) { tree[ro]=val; return; } int Mid=(L+R)>>1; updata(ro<<1,L,Mid,x,val); updata(ro<<1|1,Mid+1,R,x,val); tree[ro]=imin(tree[ro<<1],tree[ro<<1|1]);}int query(int ro,int L,int R,int li,int ri){ if(L>ri || R<li) return oo; if(li<=L && R<=ri) return tree[ro]; int Mid=(L+R)>>1; int x1=query(ro<<1,L,Mid,li,ri),x2=query(ro<<1|1,Mid+1,R,li,ri); return (imin(x1,x2));}int main(){ freopen("c.in","r",stdin); freopen("c.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d%d%d",&d[i].a,&d[i].b,&d[i].c,&d[i].d),d[i].id=i; for(int ho=0;ho<4;ho++) { pre(ho); for(int i=1;i<=n;i++) { int temp=query(1,1,n,1,dg[i].b); if(temp<dg[i].c) ffg[dg[i].id]=1; updata(1,1,n,dg[i].b,dg[i].c); } } int dell=0; for(int i=1;i<=n;i++) dell+=ffg[i]; printf("%d\n",dell); for(int i=1;i<=n;i++) if(ffg[i]) printf("%d\n",i); return 0;}
- NOIP2017提高组模拟赛 8(总结)
- NOIP2017提高组模拟赛4 (总结)
- NOIP2017提高组模拟赛5 (总结)
- NOIP2017提高组模拟赛 7(总结)
- NOIP2017提高组模拟赛 9 (总结)
- NOIP2017提高组模拟赛 10 (总结)
- NOIP2017提高组 模拟赛13(总结)
- NOIP2017提高组 模拟赛15(总结)
- NOIP2017提高组 模拟赛16(总结)
- NOIP2017提高组 模拟赛17(总结)
- NOIP2017提高组 模拟赛18(总结)
- NOIP2017提高组 模拟赛19(总结)
- NOIP2017提高组 模拟赛20(总结)
- NOIP2017提高组 模拟赛21(总结)
- NOIP2017提高组 模拟赛23(总结)
- NOIP2017提高组 模拟赛24(总结)
- NOIP2017提高组 模拟赛 26(总结)
- NOIP2017提高组 模拟赛 27(总结)
- 使用fn标签处理el表达式的值
- JavaScript权威指南学习笔记(一)2
- 开发教程地址
- 谷歌浏览器跨域
- PHP使用类对mysql的使用进行封装
- NOIP2017提高组模拟赛 8(总结)
- 创建Source Insight工程
- Intellij IDEA学习笔记
- RobotStudio仿真—Smart组件创建动态输送链
- Android NDK交叉编译环境的搭建
- jQuery动画---自定义动画animate()
- 操作系统概念(高等教育出版社,第七版)复习——第十章:文件系统接口
- word-wrap 和 word-break 属性
- Html知识点