NOIP2017提高组 模拟赛 26(总结)
来源:互联网 发布:9090端口 编辑:程序博客网 时间:2024/06/08 20:18
NOIP2017提高组 模拟赛 26(总结)
第一题 种花 (构造法/上下界的网络流)
【题目描述】
【解题思路】
①构造法:
假设现在有m个点,删除一个点,剩下的m-1个点都已经确定,那么删除的这个点应该染什么颜色。
假如这个点所在的行的点数为奇数,那么点的染色只与它所在的列有关(若列有偶数个点,那么这个点的颜色就可以确定了,哪种颜色少选哪种。否则随便选)
假如这个点所在的列的点数为奇数,与上面类似。
若不存在这样的点呢?
那么剩下的一定是所有行和列的点数皆为偶数。
那就随便选择一个点i。把它删掉。然后递归去求剩下m-1个点的情况。
那么,点i所在的行和列的点数皆为奇数,假设现在的行(除去点i)的染色是红>白,点i一定是白色。除去这个行,剩下的所有的点的红白相等。除去这个列,红白也相等。所以现在的列(除去点i)的染色也必定是红>白。所以点i为白色是可行的。(若染色情况是白>红,结果也是一样的)
递归求解即可,时间复杂度:O(n^2)。
②上下界的网络流。
S与行连边,下界为行数/2,上界为(行数+1)/2。
把每个点拆成一条边(ai,bi),下界为0,上界为1。(若有流量,则选红色)
T与列连边,下界为列数/2,上界为(列数+1)/2。
ai与点i所在的行连边,下界为0,上界为1。bi与点i所在的列连边,下界为0,上界为1。
关于上下界网络流的构图解析
【代码】
//构造法#include<cstdio>#include<algorithm>#include<cstring>using namespace std;typedef long long ll;const int N=1500;struct data { int a,b; } d[N];int w[N],n,T,row[N],lie[N],vis[N];data ry[N],ly[N];bool cmp1(int a,int b) { return (d[a].a<d[b].a); }bool cmp2(int a,int b) { return (d[a].b<d[b].b); }void dfs(int x){ if(x>n) return; bool ff=1; int yu=-1,ia,ib; for(int i=1;i<=n;i++) { if(vis[i]) continue; yu=i; ia=d[i].a; ib=d[i].b; if(row[ia]&1 || lie[ib]&1) { vis[i]=1; row[ia]--; lie[ib]--; dfs(x++); row[ia]++; lie[ib]++; if(!(row[ia]&1)) { if(ry[ia].a<ry[ia].b) ry[ia].a++,ly[ib].a++,vis[i]=2; else ry[ia].b++,ly[ib].b++,vis[i]=3; } else { if(ly[ib].a<ly[ib].b) ry[ia].a++,ly[ib].a++,vis[i]=2; else ry[ia].b++,ly[ib].b++,vis[i]=3; } ff=0; break; } } if(ff && yu!=-1) { ia=d[yu].a; ib=d[yu].b; vis[yu]=1; row[ia]--; lie[ib]--; dfs(x++); row[ia]++; lie[ib]++; if(ly[ib].a<ly[ib].b) ry[ia].a++,ly[ib].a++,vis[yu]=2; else ry[ia].b++,ly[ib].b++,vis[yu]=3; }}int main(){ freopen("2084.in","r",stdin); freopen("2084.out","w",stdout); scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1;i<=n;i++) { row[i]=lie[i]=vis[i]=0; ry[i].a=ry[i].b=0; ly[i].a=ly[i].b=0; } for(int i=1;i<=n;i++) scanf("%d%d",&d[i].a,&d[i].b),w[i]=i; sort(w+1,w+1+n,cmp1); int la=d[w[1]].a; d[w[1]].a=1; row[d[w[1]].a]++; for(int i=2;i<=n;i++) { int v=w[i]; if(d[v].a==la) d[v].a=d[w[i-1]].a; else la=d[v].a,d[v].a=d[w[i-1]].a+1; row[d[v].a]++; } sort(w+1,w+1+n,cmp2); la=d[w[1]].b; d[w[1]].b=1; lie[d[w[1]].b]++; for(int i=2;i<=n;i++) { int v=w[i]; if(d[v].b==la) d[v].b=d[w[i-1]].b; else la=d[v].b,d[v].b=d[w[i-1]].b+1; lie[d[v].b]++; } dfs(1); for(int i=1;i<=n;i++) printf("%c",(vis[i]==2)?('W'):('R')); printf("\n"); } return 0;}
//上下界网络流#include<cstdio>#include<algorithm>#include<cstring>#include<iostream>#define imin(a,b) (((a)<(b))?(a):(b))#define row(i) (i)#define ia(i) (n+i)#define ib(i) (n+n+i)#define lie(i) (n+n+n+i)using namespace std;typedef long long ll;const int inf=1e9;const int N=1500;struct data { int a,b; } d[N];int w[N],n,Tt,row[N],lie[N];int mh,ml,red[N];const int nn=1005000;int to[nn],h[nn],ne[nn],val[nn],tt;int lev[nn],vis[nn];int S,T,Sd,Td,ru[nn],bfstime;int q[nn],head,tail;bool cmp1(int a,int b) { return (d[a].a<d[b].a); }bool cmp2(int a,int b) { return (d[a].b<d[b].b); }void addedge(int a,int b,int c){ to[++tt]=b; ne[tt]=h[a]; val[tt]=c; h[a]=tt; to[++tt]=a; ne[tt]=h[b]; val[tt]=0; h[b]=tt;}void ready(){ memset(vis,0,sizeof(vis)); memset(to,0,sizeof(to)); memset(ne,0,sizeof(ne)); memset(h,0,sizeof(h)); memset(lev,-1,sizeof(lev)); memset(ru,0,sizeof(ru)); memset(val,0,sizeof(val)); tt=1; head=tail=0; S=lie(n)+10; T=S+1; Sd=T+1; Td=Sd+1; for(int i=1;i<=n;i++) row[i]=lie[i]=0; bfstime=0;}bool bfs(){ head=tail=1; q[head]=Sd; vis[Sd]=++bfstime; lev[Sd]=1; while(head<=tail) { int u=q[head++]; for(int p=h[u];p;p=ne[p]) { int v=to[p]; if(vis[v]==bfstime || !val[p]) continue; q[++tail]=v; vis[v]=bfstime; lev[v]=lev[u]+1; } } return (vis[Td]==bfstime);}int dfs(int now,int maxf){ int ret=0,t; if(now==Td || !maxf) return maxf; for(int p=h[now];p;p=ne[p]) { int v=to[p]; if(!val[p] || lev[v]!=lev[now]+1) continue; t=dfs(v,imin(maxf,val[p])); val[p]-=t; val[p^1]+=t; maxf-=t; ret+=t; } if(maxf) lev[now]=-1; return ret;}int dinic(){ int ret=0; while(bfs()) ret+=dfs(Sd,inf); return ret;}int main(){ freopen("2084.in","r",stdin); freopen("2084.out","w",stdout); scanf("%d",&Tt); while(Tt--) { scanf("%d",&n); ready(); for(int i=1;i<=n;i++) scanf("%d%d",&d[i].a,&d[i].b),w[i]=i; sort(w+1,w+1+n,cmp1); int la=d[w[1]].a; d[w[1]].a=1; row[d[w[1]].a]++; for(int i=2;i<=n;i++) { int v=w[i]; if(d[v].a==la) d[v].a=d[w[i-1]].a; else la=d[v].a,d[v].a=d[w[i-1]].a+1; row[d[v].a]++; } mh=d[w[n]].a; sort(w+1,w+1+n,cmp2); la=d[w[1]].b; d[w[1]].b=1; lie[d[w[1]].b]++; for(int i=2;i<=n;i++) { int v=w[i]; if(d[v].b==la) d[v].b=d[w[i-1]].b; else la=d[v].b,d[v].b=d[w[i-1]].b+1; lie[d[v].b]++; } ml=d[w[n]].b; for(int i=1;i<=mh;i++) { ru[S]-=row[i]>>1; ru[row(i)]+=row[i]>>1; if(row[i]&1) addedge(S,row(i),1); } for(int i=1;i<=ml;i++) { ru[T]+=lie[i]>>1; ru[lie(i)]-=lie[i]>>1; if(lie[i]&1) addedge(lie(i),T,1); } for(int i=1;i<=n;i++) { addedge(ia(i),ib(i),1); red[i]=tt; addedge(row(d[i].a),ia(i),1); addedge(ib(i),lie(d[i].b),1); } if(ru[S]>0) addedge(Sd,S,ru[S]); else if(ru[S]<0) addedge(S,Td,-ru[S]); if(ru[T]>0) addedge(Sd,T,ru[T]); else if(ru[T]<0) addedge(T,Td,-ru[T]); for(int i=1;i<=mh;i++) { if(ru[row(i)]>0) addedge(Sd,row(i),ru[row(i)]); else if(ru[row(i)]<0) addedge(row(i),Td,-ru[row(i)]); } for(int i=1;i<=ml;i++) { if(ru[lie(i)]>0) addedge(Sd,lie(i),ru[lie(i)]); else if(ru[lie(i)]<0) addedge(lie(i),Td,-ru[lie(i)]); } addedge(T,S,inf); int maxflow=dinic(); for(int i=1;i<=n;i++) printf("%c",(val[red[i]]?('W'):('R'))); printf("\n"); } return 0;}
第二题 X之谜 (背包DP)
【题目描述】
【解题思路】
①首先确定的是,顺序是没关系的,只需求出来选数的方案数就成。因为选好了,一定可以按题意排好序的。
②把数按照模k的值分类。因为对答案有影响的也只是模数而已。
③背包DP。F[i][j][h]表示做到了模为i的数,已经选了j个数,模数为h的方案数。
那么,假设在模为i的数中选了g个数,选法有w种。
F[i][j+g][(h+g*i)%k]+=F[i-1][j][h]*w;
那,w怎么求?
假设,模为i的有s个数。
那么,就相当于把g个小球放入s个桶的方案数。
建立g个小球,再加入s-1个挡板。第i个挡板到第i-1个挡板之间的球就是桶i里的小球个数,第s个桶的小球数为剩下的小球数(第s-1个挡板之后的小球)
只需求出放挡板的方案数,就是小球放入桶里的方案数。
方案数=C(s+g-1,s-1),也就是C(s+g-1,g)
④因为C(n+m,n)=C(n+m,m),拓展证出,交换n,m的值,答案不变。
算组合方案时,要用到逆元……
【代码】
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;typedef long long ll;const int mods=2017;int T,n,m,k;int c[55],cs[5];ll f[55][55][55],sq[5][55];ll Pow(ll x,ll y){ ll s=1; for(;y;y>>=1) { if(y&1) s=s*x%mods; x=x*x%mods; } return s;}int main(){ freopen("2085.in","r",stdin); freopen("2085.out","w",stdout); scanf("%d",&T); while(T--) { scanf("%d%d%d",&n,&m,&k); if(n<m) swap(n,m); memset(f,0,sizeof(f)); for(int i=0;i<k;i++) c[i]=0; int yc=n/k; cs[0]=yc; cs[1]=yc+1; yc=n%k; for(int i=0;i<=yc;i++) c[i]=1; for(int i=0;i<2;i++) { ll sd; int yr=cs[i]; for(int j=0;j<=m;j++) { sd=1ll; for(int h=1;h<=j;h++) sd=sd*(yr+j-h)%mods*Pow(h,mods-2)%mods; sq[i][j]=sd; } } for(int i=0;i<=m;i++) f[0][i][0]=sq[c[0]][i]; for(int i=0;i<k-1;i++) for(int j=0;j<=m;j++) for(int h=0;h<k;h++) if(f[i][j][h]) { for(int co=0;co<=m-j;co++) { int yu=(h+(i+1)*co%k)%k; (f[i+1][j+co][yu]+=(f[i][j][h]*sq[c[i+1]][co])%mods)%=mods; } } printf("%lld\n",f[k-1][m][0]); } return 0;}
第三题 大数开方 (模拟题)
【题目描述】
【解题思路】
按照题意模拟即可。
【代码】
#include<cstdio>#include<algorithm>#include<cstring>int l,w;int ans[1500];int work(int o,char *O,int I){ char c,*D=O; if(o>0) { for(l=0;D[l];D[l++]-=10) { D[l++]-=120; D[l]-=110; while(!work(0,O,l)) D[l]+=20; ans[++w]=((D[l]+120-48)/20); } } else { if(I>=0) c=o+(D[I]+130-48)%10-(I>l/2)*(D[I-l+I]+120-48)/10-9; if(I>=0) D[I]+=!(o=work(c/10,O,I-1))*((c+999)%10-(D[I]+140-48)%10); } return o;}int main(){ freopen("2086.in","r",stdin); freopen("2086.out","w",stdout); char s[1200];s[0]='0'; scanf("%s",s+1); int sl=strlen(s); char sp[]="0000000000000000000000"; strcat(s,sp); if(sl&1) work(2,s+1,0); else work(2,s,0); if(ans[w]>4) ans[w-1]++; for(int i=1;i<=w-11;i++) printf("%d",ans[i]); printf("."); for(int i=w-10;i<=w-1;i++) printf("%d",ans[i]); printf("\n"); return 0;}
- NOIP2017提高组 模拟赛 26(总结)
- NOIP2017提高组模拟赛4 (总结)
- NOIP2017提高组模拟赛5 (总结)
- NOIP2017提高组模拟赛 7(总结)
- NOIP2017提高组模拟赛 8(总结)
- 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提高组 模拟赛 27(总结)
- 简单的java程序
- java算数运算符之加法
- python里使用正则表达式的限制边界功能
- angular设置一个定时器
- 拍照打开相册
- NOIP2017提高组 模拟赛 26(总结)
- OkHttp3Utils的封装
- markdown编辑器中数学公式的基本命令
- python模块之pickle模块(这是python3中为import pickle,python2中为import cPickle as pickle)
- iOSBlock函数声明定义以及调用等
- sysu-17C04签到
- 持续集成:Jmeter+Maven+Jenkins自动化框架搭建(三):Jenkins配置
- java输入两个整数,求和.
- 21分钟 MySQL 入门教程