NOIP2017提高组 模拟赛18(总结)
来源:互联网 发布:大都会歌剧院 知乎 编辑:程序博客网 时间:2024/06/08 08:14
NOIP2017提高组 模拟赛18(总结)
第一题 火柴
【题目描述】
【解题思路】
从左往右扫一遍,优先满足第i位,若ai>ave,则将多余的火柴移到第i+1位;若ai<ave,则将i+1位的ave-ai个移到第i位(即使将第i+1位变成负数也没关系,因为第i+1位也可以从后面拿),统计移动次数即可。
【代码】
#include<cstdio>#include<algorithm>using namespace std;typedef long long ll;const int N=50050;ll d[N],sum,ans;int n;int main(){ freopen("2247.in","r",stdin); freopen("2247.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lld",&d[i]),sum+=d[i]; sum=sum/n; for(int i=1;i<n;i++) { if(d[i]>sum) d[i+1]+=d[i]-sum,ans+=d[i]-sum,d[i]=sum; else d[i+1]-=sum-d[i],ans+=sum-d[i],d[i]=sum; } printf("%lld\n",ans); return 0;}
第二题 管理者
【题目描述】
【解题思路】
先求出最小生成树,假如ui->vi必须升级,则在ui->vi的路径上找出最大的边,替换掉就行了。
如何快速求路径最大值呢?
LCT可以很好的解决这一问题(滑稽)
其实用树上倍增就足够了。
【代码】
#include<cstdio>#include<algorithm>#define imax(a,b) ((a>b)?(a):(b))using namespace std;typedef long long ll;const int N=200500;struct tree{ tree *f,*c[2],*pp; int val,mx; bool flip; int d() { return (f->c[1]==this); } void sc(tree *x,int d) { (c[d]=x)->f=this; }} nil[N<<2],*ro[N<<2],*stack[N<<2];struct data{ int l,r,cost,id;} road[N];int f[N],n,m,cnt;ll ans;void down(tree *x){ if(x==nil) return; if(x->flip) { swap(x->c[0],x->c[1]); if(x->c[0]!=nil) x->c[0]->flip^=1; if(x->c[1]!=nil) x->c[1]->flip^=1; x->flip=0; }}void up(tree *x){ if(x==nil) return; x->mx=x->val; if(x->c[0]!=nil) x->mx=imax(x->mx,x->c[0]->mx); if(x->c[1]!=nil) x->mx=imax(x->mx,x->c[1]->mx);}tree *newtree(){ nil[++cnt]=nil[0]; return nil+cnt;}void rotate(tree *x){ int d=x->d(); tree *y=x->f; y->sc(x->c[!d],d); if(y->f==nil) x->f=nil; else y->f->sc(x,y->d()); x->sc(y,!d); x->pp=y->pp; y->pp=nil; up(y); up(x);}void splay(tree *x){ int hy=1; stack[hy]=x; for(;stack[hy]->f!=nil;hy++) stack[hy+1]=stack[hy]->f; for(int i=hy;i>=1;i--) down(stack[i]); for(tree *y;x->f!=nil;) { y=x->f; if(y->f!=nil) (y->d()^x->d())?rotate(x):rotate(y); rotate(x); }}void access(tree *x){ tree *y=nil; while(x!=nil) { splay(x); if(x->c[1]!=nil) { x->c[1]->f=nil; x->c[1]->pp=x; } x->c[1]=y; if(y!=nil) { y->f=x; y->pp=nil; } up(x); y=x; x=x->pp; }}void evert(tree *x){ access(x); splay(x); x->flip^=1;}void link(tree *x,tree *y){ evert(y); splay(y); y->pp=x;}bool cmp(data A,data B) { return (A.cost<B.cost); }bool cmp1(data A,data B) { return (A.id<B.id); }int find(int x) { return ((f[x]<0)?(x):(f[x]=find(f[x]))); }void uni(int now){ int x1=find(road[now].l),x2=find(road[now].r); if(x1==x2) return; ans+=road[now].cost; link(ro[road[now].l],ro[n+road[now].id]); link(ro[road[now].r],ro[n+road[now].id]); if(f[x1]>f[x2]) swap(x1,x2); f[x1]+=f[x2]; f[x2]=x1;}int findmax(tree *x,tree *y){ evert(x); access(y); splay(y); return y->mx;}int main(){ freopen("2248.in","r",stdin); freopen("2248.out","w",stdout); cnt=0; nil->f=nil->pp=nil->c[0]=nil->c[1]=nil; nil->mx=nil->val=0; nil->flip=0; scanf("%d%d",&n,&m); ans=0ll; for(int i=1;i<=n;i++) ro[i]=newtree(); for(int i=1;i<=m;i++) { scanf("%d%d%d",&road[i].l,&road[i].r,&road[i].cost),road[i].id=i; ro[n+i]=newtree(); ro[n+i]->val=ro[n+i]->mx=road[i].cost; } sort(road+1,road+1+m,cmp); for(int i=1;i<=n;i++) f[i]=-1; for(int i=1;i<=m;i++) uni(i); sort(road+1,road+1+m,cmp1); for(int i=1;i<=m;i++) { int yu=findmax(ro[road[i].l],ro[road[i].r]); printf("%lld\n",ans-yu+road[i].cost); } return 0;}
第三题 数学家
【题目描述】
【解题思路】
记g[h][i]为长度为h的南墙,用i块草坪去铺的最小面积。
记f[h][i][j]为长度为h的南北墙,北墙用i块草坪,南墙用j块草坪去铺的最小面积。
h1<h,j1<j
时间复杂度:O(N^5) 显然超时……
其实这具有决策单调性,因为
假若f[h][i-1][j]的决策是h1,j1,f[h][i][j]的决策是h2,j2,必定存在h2>h1,j2>j1。
利用这一决策单调性可以除去一维,时间复杂度:O(N^4)
加了许多优化,程序跑的飞快……
千万记得判是否越界,例如草坪数要永远不超过墙的长度。
没有注意,WA了好多次
【代码】
#include<cstdio>#include<algorithm>#define imax(a,b) ((a>b)?(a):(b))#define imin(a,b) ((a<b)?(a):(b))using namespace std;typedef long long ll;const int N=120;double f1,f2;int n,m;struct data { int l,p; } d[N][N][N];double g[N][N],f[N][N][N];int main(){ freopen("2249.in","r",stdin); freopen("2249.out","w",stdout); scanf("%lf%lf%d%d",&f1,&f2,&n,&m); for(int i=1;i<=100;i++) { g[i][0]=1e9; g[i][1]=i*i; for(int j=2;j<=i;j++) { int yu=i/j; g[i][j]=g[i-yu][j-1]+yu*yu; } } for(int i=1;i<=100;i++) { for(int j=1;j<=m;j++) { f[i][j][1]=i*i*f1+g[i][j]*f2; d[i][j][1].l=0; d[i][j][1].p=0; } } for(int h=2;h<=100;h++) { int mi=imin(h,m),mj=imin(h,n); for(int i=2;i<=mi;i++) { for(int j=2;j<=imin(i,mj);j++) { int sh=imax(1,d[h][i][j-1].l),si=imax(imax(1,d[h][i][j-1].p),j-1); f[h][i][j]=1e9; for(int h1=sh;h1<=h;h1++) { /*if(h==100 && i==100 && h1==50) printf("ok\n");*/ double getans=1e9; int kl,kp; int gh=h-h1; int ip=imax(i-gh,si),mip=imin(h1,i); for(int i1=ip;i1<=mip;i1++) { double yu=f[h1][i1][j-1]+gh*gh*f1+g[gh][i-i1]*f2; if(yu>getans) break; getans=yu; kl=h1; kp=i1; } if(getans<f[h][i][j]) { f[h][i][j]=getans; d[h][i][j].l=kl; d[h][i][j].p=kp; } } //printf("%d %d %d %.lf\n",h,i,j,f[h][i][j]); } } } printf("%.1lf\n",f[100][m][n]); return 0;}
阅读全文
0 0
- NOIP2017提高组 模拟赛18(总结)
- NOIP2017提高组模拟赛4 (总结)
- NOIP2017提高组模拟赛5 (总结)
- NOIP2017提高组模拟赛 7(总结)
- NOIP2017提高组模拟赛 8(总结)
- NOIP2017提高组模拟赛 9 (总结)
- NOIP2017提高组模拟赛 10 (总结)
- NOIP2017提高组 模拟赛13(总结)
- NOIP2017提高组 模拟赛15(总结)
- NOIP2017提高组 模拟赛16(总结)
- NOIP2017提高组 模拟赛17(总结)
- NOIP2017提高组 模拟赛19(总结)
- NOIP2017提高组 模拟赛20(总结)
- NOIP2017提高组 模拟赛21(总结)
- NOIP2017提高组 模拟赛23(总结)
- NOIP2017提高组 模拟赛24(总结)
- NOIP2017提高组 模拟赛 26(总结)
- NOIP2017提高组 模拟赛 27(总结)
- HDU 2571 命运 【简单动态规划】
- 欢迎使用CSDN-markdown编辑器
- XML
- 关于 Sublime Text 3 清空缓存文件(之前打开的文件)
- 新路程------imx lvds 大屏没有点亮
- NOIP2017提高组 模拟赛18(总结)
- 【学习摘记】马士兵bbs改良版_课时1-4_MyEclipse安装及运行
- HGDB pg_xlog个数
- #Java学习笔记(2)
- Python上下文管理器
- java学习之 JSONObject
- 编译原理
- laypage分页
- >