NOIP2017提高组 模拟赛23(总结)
来源:互联网 发布:mac怎么删除硬盘文件 编辑:程序博客网 时间:2024/05/22 14:11
NOIP2017提高组 模拟赛23(总结)
第一题 Hacker
【题目描述】
【解题思路】
只需要两段假期,而且天数也不会超过10^6。直接用数组记下就好。排个序,遇头统计前面的是否有符合的,遇尾就把这段假期加进数组里。
【代码】
#include<cstdio>#include<algorithm>#define imin(a,b) ((a<b)?(a):(b))using namespace std;const int N=1000100;const int oo=1000000100;int n,m,n2,ans;int L[N],R[N],X[N],mm[N];struct data { int x,id; bool fl; } d[N<<1];bool cmp(data A,data B) { return (A.x<B.x || (A.x==B.x && (A.fl==0 && B.fl==1))); }int main(){ freopen("1982.in","r",stdin); freopen("1982.out","w",stdout); scanf("%d%d",&n,&m); for(int i=0;i<=m;i++) mm[i]=oo; for(int i=1;i<=n;i++) { scanf("%d%d%d",&L[i],&R[i],&X[i]); d[i].id=i; d[i].x=L[i]; d[i].fl=0; d[i+n].id=i; d[i+n].x=R[i]; d[i+n].fl=1; } n2=n<<1; sort(d+1,d+1+n2,cmp); ans=oo<<1; for(int i=1;i<=n2;i++) { int id=d[i].id; int len=R[id]-L[id]+1; if(d[i].fl==1) mm[len]=imin(mm[len],X[id]); else { if(len>=m) continue; if(mm[m-len]!=oo) ans=imin(ans,mm[m-len]+X[id]); } } printf("%d\n",(ans==(oo<<1))?(-1):(ans)); return 0;}
第二题 记字符串 (状压DP)
【题目描述】
【解题思路】
字符串的长度和个数都不超过20。
假如,要用第i位来使第i位相同的字符串独立,有两种情况:
①将所有相同的字符改成其他字符,最大的不用改。
代价=所有第i位相同的字符串改第i位的代价的总和-字符串改第i位的最大代价。
②还有一种就是改单个字符。
代价=最小的改一位的代价(从1~m位中改最小代价的那一位)。
因为只有20个字符串,一定可以改成与其他字符不同的字符。
状态压缩DP。
记现在处理到第w位,已经独立的字符串的状态为S的最小代价。
预处理出将第i个字符串的第j位改掉(用① 的改法),所影响的字符串集合Wij.S,代价为Wij.cost。
还有第②中改法的单个字符串i最小代价mn[i]。
找出S的未被独立的最小的i。
①枚举改第j位。
②
【代码】
#include<cstdio>#include<cstring>#include<algorithm>#define imax(a,b) ((a>b)?(a):(b))#define imin(a,b) ((a<b)?(a):(b))#define fn (1<<n)using namespace std;const int inf=1e9;const int N=25;const int big=1500000;int n,m;struct data { int stu,cs; } w[N][N];int cs[N][N],d[N][N],f[big],mn[N];char st[N];int main(){ freopen("1983.in","r",stdin); freopen("1983.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%s",st); for(int j=0;j<m;j++) d[i][j+1]=st[j]-'a'+1; } for(int i=1;i<=n;i++) { mn[i]=inf; for(int j=1;j<=m;j++) scanf("%d",&cs[i][j]),mn[i]=imin(mn[i],cs[i][j]); } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { int ysum=0,mx=0; int stu=0; for(int h=1;h<=n;h++) if(d[h][j]==d[i][j]) { stu+=(1<<(h-1)); ysum+=cs[h][j]; mx=imax(mx,cs[h][j]); } w[i][j].stu=stu; w[i][j].cs=ysum-mx; } } for(int i=1;i<fn;i++) f[i]=inf; f[0]=0; for(int i=0;i<fn;i++) if(f[i]!=inf) { int last=0; while(i&(1<<last)) last++; if(last>=n) continue; int yu; for(int j=1;j<=m;j++) { yu=i|(w[last+1][j].stu); f[yu]=imin(f[yu],f[i]+w[last+1][j].cs); } yu=i|(1<<(last)); f[yu]=imin(f[yu],f[i]+mn[last+1]); } printf("%d\n",f[fn-1]); return 0;}
第三题 士兵与旅行 (网络流)
【题目描述】
【解题思路】
城市和道路构成一幅图,每一个城市的士兵只能去相邻的城市。一开始的状态为S1,结束状态为S2。
先在需要从S1转到S2。
可以对每一个城市建立两个点Ai,Bi,分别表示转移之前的和转移之后的。
若城市i可以到达城市j,则Ai->Bj,流量无穷大。(因为士兵可以从i转移到j,流了多少就表示转移多少)
从源点S->城市i,流量为一开始城市i的士兵数。
城市i->汇点T,流量为转移之后的士兵数。
判断流出流量是否等于流入流量就好。
若等于,则一定存在转移方案。城市Ai->城市Bj的反向边的流量就是转移方案(因为记录的是剩余流量,开始为∞,流了w,变成∞-w。那么反向边的流量就是w)。
【代码】
#include<cstdio>#include<algorithm>#define imax(a,b) ((a>b)?(a):(b))#define imin(a,b) ((a<b)?(a):(b))#define ad(i) (i)#define bd(i) (n+i)using namespace std;const int inf=1e9;const int N=120;const int M=220;const int maxm=1000000;int n,m,sum_a,sum_b;int A[N],B[N];int bfstime,q[maxm],lev[maxm],vis[maxm];int h[maxm],d0,S,T;int yu[N][N];struct data { int val,to,ne; } d[maxm];void addedge(int a,int b,int c){ d0++; d[d0].to=b;d[d0].val=c;d[d0].ne=h[a];h[a]=d0; d0++; d[d0].to=a;d[d0].val=0;d[d0].ne=h[b];h[b]=d0;}bool bfs(){ int head=1,tail=1; q[head]=S; vis[S]=++bfstime; lev[S]=1; while(head<=tail) { for(int p=h[q[head]];p;p=d[p].ne) { if(!d[p].val) continue; int to=d[p].to; if(vis[to]==bfstime) continue; q[++tail]=to; vis[to]=bfstime; lev[to]=lev[q[head]]+1; } head++; } return vis[T]==bfstime;}int dfs(int now,int maxf){ int ret=0,t; if(now==T || !maxf ) return maxf; for(int p=h[now];p;p=d[p].ne) { int to=d[p].to; if(!d[p].val || lev[to]!=lev[now]+1) continue; t=dfs(to,imin(maxf,d[p].val)); d[p].val-=t; d[p^1].val+=t; maxf-=t; ret+=t; } if(maxf) lev[now]=-1; return ret;}int dinic(){ int ret=0; while(bfs()) ret+=dfs(S,1e9); return ret;}int main(){ freopen("1984.in","r",stdin); freopen("1984.out","w",stdout); scanf("%d%d",&n,&m); d0=1; S=(n<<1)+1; T=S+1; sum_a=sum_b=0; for(int i=1;i<=n;i++) { scanf("%d",&A[i]); addedge(S,ad(i),A[i]); sum_a+=A[i]; } for(int i=1;i<=n;i++) { scanf("%d",&B[i]); addedge(bd(i),T,B[i]); addedge(ad(i),bd(i),inf); sum_b+=B[i]; } for(int i=1;i<=m;i++) { int a,b; scanf("%d%d",&a,&b); addedge(ad(a),bd(b),inf); addedge(ad(b),bd(a),inf); } int sum_la=dinic(); if(sum_la==sum_b) { printf("YES\n"); for(int i=1;i<=n;i++) { int u=bd(i); for(int p=h[u];p;p=d[p].ne) { if(!(p&1)) continue; int to=d[p].to; yu[to][i]+=d[p].val; } } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) printf("%d ",yu[i][j]); printf("\n"); } } else printf("NO\n"); return 0;}
- NOIP2017提高组 模拟赛23(总结)
- 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提高组 模拟赛24(总结)
- NOIP2017提高组 模拟赛 26(总结)
- NOIP2017提高组 模拟赛 27(总结)
- es6的十大特性
- java多线程定义及线程安全
- 论文发表费用怎样更省钱
- codevs 2370 小机房的树 LCA 解题报告
- python 把json数据导入mongodb数据库
- NOIP2017提高组 模拟赛23(总结)
- 关于fold
- 史上最全的maven的pom.xml文件详解
- Mysql-事务隔离级别
- javascript 实现页面间传值(3) 解决中文乱码问题
- python迭代器问题
- eclipse Springboot,Spring整合lombook
- Programming with MicroPython.pdf 英文原版 免费下载
- 手机用wifi下载软件无法安装,提示应用未安装