洛谷P1295:[TJOI2011]书架 (线段树优化DP)
来源:互联网 发布:java finalize 异常 编辑:程序博客网 时间:2024/06/05 15:42
题目传送门:https://www.luogu.org/problemnew/show/P1295
题目分析:这题是我在NOIP之前看到的,那个时候我们机房人人都在刷这题,而我因为在颓,就只好事后填坑啦。
按tututu的话来说,“这题不难想,其实怎么做都可以”,主要是因为有很多单调性。
首先
其中对于每一个i,j的最小值是可以预处理出来的,记为Left[i],并且Left数组单调不降。
而且很明显f值也是单调不降的。而且若i固定,随着j越小,a[j]~a[i]的max值也是单调不降的,我们可以画个图:
很明显只有蓝色部分(即max值变化了的地方)的j值才有可能作为答案,我们只需要算这些地方贡献的最小值即可。那么假设新来了一个a[i+1]呢?
假设我们已经用一个双端队列存储了j1,j2,j3。我们发现j2~i,j3~i的max值小于a[i+1],于是将其弹出,最后将f[j2]+a[i+1]加进来。然后再考虑Left对转移的限制。比如j1小于Left[i],就要将其弹出队列,但最优答案可能会刚好取到Left[i],所以还要让它本身进入队列。同时用数据结构维护队列里贡献的最小值,时间
写代码的时候,有一个细节没有考虑好,就是如果Left[i]已经在队列里面,就不用再进队了,然而我判的时候没有考虑head>tail,即队列为空的情况,导致越界了。
CODE:
#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<cstdlib>#include<stdio.h>#include<algorithm>using namespace std;const int maxn=100100;const int oo=1000000000;int tree[maxn<<2];int Left[maxn];int Max[maxn];struct data{ int val,id,Time;} h[maxn];int sum[maxn];int temp;int que[maxn];int g[maxn];int head=1,tail=0;int f[maxn];int n,m;bool Comp1(data x,data y){ return x.val<y.val;}bool Comp2(data x,data y){ return x.Time<y.Time;}int Query(int root,int L,int R,int x,int y){ if ( y<L || R<x ) return 0; if ( x<=L && R<=y ) return tree[root]; int mid=(L+R)>>1; int Left=root<<1; int Right=Left|1; int vl=Query(Left,L,mid,x,y); int vr=Query(Right,mid+1,R,x,y); return max(vl,vr);}void Update_max(int root,int L,int R,int x,int v){ if (L==R) { tree[root]=v; return; } int mid=(L+R)>>1; int Left=root<<1; int Right=Left|1; if (x<=mid) Update_max(Left,L,mid,x,v); else Update_max(Right,mid+1,R,x,v); tree[root]=max(tree[Left],tree[Right]);}void Update(int root,int L,int R,int x,int v){ if (L==R) { tree[root]=v; return; } int mid=(L+R)>>1; int Left=root<<1; int Right=Left|1; if (x<=mid) Update(Left,L,mid,x,v); else Update(Right,mid+1,R,x,v); tree[root]=min(tree[Left],tree[Right]);}int main(){ freopen("1295.in","r",stdin); freopen("1295.out","w",stdout); scanf("%d%d",&n,&m); for (int i=1; i<=n; i++) scanf("%d",&h[i].val),h[i].Time=i; sort(h+1,h+n+1,Comp1); temp=h[1].id=1; for (int i=2; i<=n; i++) if (h[i-1].val==h[i].val) h[i].id=temp; else h[i].id=++temp; sort(h+1,h+n+1,Comp2); for (int i=1; i<=n; i++) { Max[i]=Query(1,1,temp,h[i].id,temp); Update_max(1,1,temp,h[i].id,i); } sum[0]=0; for (int i=1; i<=n; i++) sum[i]=sum[i-1]+h[i].val; Left[1]=0; for (int i=2; i<=n; i++) { Left[i]=Left[i-1]; while ( sum[i]-sum[ Left[i] ]>m ) Left[i]++; } for (int i=0; i<(n<<2); i++) tree[i]=oo; Update(1,1,n+1,1,0); que[++tail]=0; g[tail]=0; for (int i=1; i<=n; i++) { while ( head<=tail && que[tail]>=Max[i] ) Update(1,1,n+1,que[tail]+1,oo),tail--; Update(1,1,n+1,Max[i]+1,f[ Max[i] ]+h[i].val); tail++; que[tail]=Max[i]; g[tail]=h[i].val; int tp=oo; while ( head<=tail && que[head]<Left[i] ) tp=g[head],Update(1,1,n+1,que[head]+1,oo),head++; if ( tp<oo && ( que[head]!=Left[i] || head>tail ) ) head--,que[head]=Left[i],g[head]=tp, Update(1,1,n+1,Left[i]+1,f[ Left[i] ]+tp); f[i]=tree[1]; tail++; que[tail]=i; g[tail]=0; Update(1,1,n+1,i+1,f[i]); } printf("%d\n",f[n]); return 0;}
阅读全文
0 0
- 洛谷P1295:[TJOI2011]书架 (线段树优化DP)
- 洛谷1295:书架(堆优化dp)
- 洛谷 P1377 [TJOI2011]树的序
- zoj 2900 DP(线段树优化)
- bzoj1835(线段树优化dp)
- ZJU3349 线段树优化DP
- 数据--dp,线段树优化
- cf343D dp+线段树优化
- ZOJ 3349 Special Subsequence(DP+线段树优化)
- ZOJ 3650 Toy Blocks(DP + 线段树优化转移)
- ZOJ 3349 Special Subsequence(线段树优化DP)
- zoj 3349 Special Subsequence(dp+线段树优化)
- code vs 3289 花匠 (线段树优化dp)
- bzoj 3790: 神奇项链 (manacher+线段树优化DP)
- ZOJ 3349 Special Subsequence(DP+线段树优化)
- ZOJ 3650 Toy Blocks(DP + 线段树优化转移)
- bzoj1835 [ZJOI2010]base 基站选址(dp+线段树优化)
- CodeForces 833B The Bakery(dp+线段树优化)
- Python操作MySQL数据库实例
- 字符指针变量和字符数组的讨论
- 使用BottomTabBar实现类似Fragment页面切换
- 浏览列表有关的对象
- 一点一滴成就生活
- 洛谷P1295:[TJOI2011]书架 (线段树优化DP)
- Qt异形窗口
- 基于dubbo从传统MVC架构转向SOA架构分布式设计3--(zookeeper集群)
- HDU 3695 Computer Virus on Planet Pandora AC自动机
- Qt安装教程
- Android新手上路-AndroidStudio3.0升级后不能自动生成aar
- 演讲实录 | 招银云创:容器PaaS正在让开发人员再也看不到IaaS
- Java分页
- offset、client、scroll:width、height、left、top