SPOJ1748 - SEQPAR2 二分答案 DP优化 单调队列+线段树
2014-04-09 15:15
507 查看
题目太蛋疼。。
首先有一个N^2LIMIT的最最暴力的DP。囧
然后可以换个DP的东西,二分答案,然后DP验证是否可行。(f
<=LIMIT)
对于第一个条件,其实可以与处理出来最小的必须在一起的块。然后合并起来。然后第一个条件就没了。
然后就要考虑第二个条件了。
还是二分答案,DP验证 。但是N^2的暴力DP肯定要TLE的。
考虑优化一下dp.
转移是:
f[i]=Min{f[j]+MaxA(j+1,i)} sumb(j+1,i)≤X (x是当前二分的答案)
然后这玩意儿竟然可以优化。
MaxA(j+1,i)是随j变大单调不增的。
然后考虑以A为关键字建一个单调递减的栈。
然后用线段树维护f[j]+MaxA(j+1,i) 整个的值
但是修改的只是MaxA(j+1,i)
MaxA(j+1,i)是成段变化的,每次加上一个差值就可以了。
但是f[j]+MaxA(j+1,i) 是不单调的。所以要在线段树里面询问最小值
然后修改一段区间是logN的 ,每个点最多单独更新一次。每次DP是NlogN的。
下面是错误的代码。。。(为啥还放上来 。。)
首先有一个N^2LIMIT的最最暴力的DP。囧
然后可以换个DP的东西,二分答案,然后DP验证是否可行。(f
<=LIMIT)
对于第一个条件,其实可以与处理出来最小的必须在一起的块。然后合并起来。然后第一个条件就没了。
然后就要考虑第二个条件了。
还是二分答案,DP验证 。但是N^2的暴力DP肯定要TLE的。
考虑优化一下dp.
转移是:
f[i]=Min{f[j]+MaxA(j+1,i)} sumb(j+1,i)≤X (x是当前二分的答案)
然后这玩意儿竟然可以优化。
MaxA(j+1,i)是随j变大单调不增的。
然后考虑以A为关键字建一个单调递减的栈。
然后用线段树维护f[j]+MaxA(j+1,i) 整个的值
但是修改的只是MaxA(j+1,i)
MaxA(j+1,i)是成段变化的,每次加上一个差值就可以了。
但是f[j]+MaxA(j+1,i) 是不单调的。所以要在线段树里面询问最小值
然后修改一段区间是logN的 ,每个点最多单独更新一次。每次DP是NlogN的。
下面是错误的代码。。。(为啥还放上来 。。)
#include <cstdio> #include <algorithm> #define per(i,r,l) for (int i=r;i>=l;--i) #define rep(i,l,r) for (int i=l;i<=r;++i) typedef unsigned int UI; bool upmax(int &a,int b){return a<b?a=b,1:0;} bool upmax(UI &a,UI b){return a<b?a=b,1:0;} UI Max(UI a,UI b){return a<b?b:a;} const int MAX_N=50050; UI n,lim; UI a[MAX_N],b[MAX_N]; UI sum[MAX_N]; void New(){ static UI max[MAX_N]; per(i,n,1) max[n-i+1]=Max(max[n-i],a[i]); static int L[MAX_N],R[MAX_N],top=0; bool fir=true;int r=0; rep(i,1,n){ upmax(r,n-(std::lower_bound(max,max+n-i+1,b[i])-max)+1); if (fir) L[++top]=i,fir=0; if (i==r) R[top]=i,fir=1; } n=top; rep(i,1,top){ UI s=0,mx=0; rep(j,L[i],R[i]) upmax(mx,a[j]),s+=b[j]; a[i]=mx,b[i]=s; sum[i]=sum[i-1]+b[i]; } } int getp(UI *a,int l,int r,int v){ if (v<a[l]) return l; while (r-l>1){ int mid=l+r>>1; if (v>a[mid]) r=mid; else l=mid; } return r; } bool check(UI x){ static UI f[MAX_N],que1[MAX_N],que2[MAX_N]; int h1=0,t2=0,h2=0; que2[t2]=0;f[0]=0; rep(i,1,n){ while(0<h1&&a[que1[h1]]<=a[i]) h1--; que1[++h1]=i; while(t2<h2&&((sum[i]-sum[que2[t2]])>x)) t2++; f[i]=f[que2[t2]]+a[getp(que1,1,h1,que2[h2])]; //printf("%d\n",f[i]); while(t2<h2&&( f[que2[h2]]+a[getp(que1,1,h1,que2[h2])] >f[i] + a[getp(que1,1,h1,i)])) h2--; que2[++h2]=i; } return f <=lim; } void Solve(){ UI l=0,r=1; rep(i,1,n) upmax(l,b[i]-1),r+=b[i]; while (r-l>1){ UI mid=l+r>>1; if (check(mid)) r=mid; else l=mid; } printf("%d\n",r); } int main(){ freopen("partition.in","r",stdin); freopen("partition.out","w",stdout); scanf("%u%u",&n,&lim); rep(i,1,n) scanf("%u%u",&a[i],&b[i]); New(); //rep(i,1,n) printf("%d %d\n",a[i],b[i]); //check(9); Solve(); }
相关文章推荐
- 【NOIP2017普及组T4】跳房子-二分答案+DP单调队列优化
- NKOJ 4244 (HAOI 2008) 木棍分割 (二分答案+DP+单调队列+前缀和优化+滚动数组)
- NOIP模拟赛 军训(二分答案+单调队列优化DP)
- BZOJ 2806: [Ctsc2012]Cheat [广义后缀自动机 单调队列优化DP 二分]
- wikioi-1748 瑰丽华尔兹 -单调队列优化DP
- 线段树和单调队列优化DP---POJ2373解题报告
- bzoj2806 [Ctsc2012]Cheat(单调队列优化dp+二分+广义SAM)
- 【日常学习】【二分】【单调队列优化线性DP】codevs3342 绿色通道题解
- [二分 后缀自动机 单调队列优化DP] BZOJ 2806 [Ctsc2012]Cheat
- 【BZOJ2806】[Ctsc2012]Cheat 广义后缀自动机+二分+单调队列优化DP
- 线段树和单调队列优化DP
- NKOJ 2650 (SDOI 2011) 消防(树的直径+DP+单调队列/二分答案)
- [BZOJ 2500]幸福的道路 树形dp+单调队列+二分答案
- bzoj1499: [NOI2005]瑰丽华尔兹&&codevs1748 单调队列优化dp
- 线段树和单调队列优化DP---POJ2373解题报告
- BZOJ2806 [Ctsc2012]Cheat 【后缀自动机 + 二分 + 单调队列优化DP】
- DP的各种优化(动态规划,决策单调性,斜率优化,带权二分,单调栈,单调队列)
- 【bzoj2806】[Ctsc2012]Cheat 广义后缀自动机+二分+单调队列优化dp
- BZOJ_1044_[HAOI2008]木棍分割_二分答案+DP+单调队列
- HAOI2008 木棍分割 二分答案 前缀和优化 单调队列 滚动数组