[BZOJ 2436][NOI 2011]NOI嘉年华(DP优化)
2015-04-24 21:42
323 查看
题目链接
http://www.lydsy.com/JudgeOnline/problem.php?id=2436思路
这个题做起来很复杂很繁琐。。。以下思路整理自/article/2926787.html首先将所有的区间离散化,这一步很好实现。
然后就是求三个数组num[i][j],pre[i][j],suf[i][j]num[i][j],pre[i][j],suf[i][j]
num[i][j]=[i,j]num[i][j]=[i,j]区间内的线段个数。
pre[i][j]=[0,i]pre[i][j]=[0,i]区间内给B jj个线段,A得到最多线段个数。
suf[i][j]=[j,∞)suf[i][j]=[j,\infty)区间内给B jj个线段,A得到最多线段个数。
容易推出num[i][j]num[i][j]。我们枚举ii,对于所有左端点LtL_t大于等于ii的区间右端点RtR_t,标记num′[i][Rt]++num'[i][R_t]++,那么显然num[i][j]=∑jk=inum′[i][k]num[i][j]=\sum_{k=i}^jnum'[i][k],这一个求和的步骤,可以将所有的num[i][t]num[i][t]在O(n)O(n)时间内通过递推求前缀和的形式求出。
然后就是pre[i][j]和suf[i][j]pre[i][j]和suf[i][j]了,这两个其实基本上一样,下面只讲pre[i][j]pre[i][j]的求法。
pre[i][j]=max{max0≤k<i{pre[k][j]+num[k][i],pre[k][j−num[k][i]]}}pre[i][j]=\max \{ \max_{0\leq k
(注:区间[0,i][0,i]中给B放入jj个线段,可以枚举k<ik,要么在区间[0,k][0,k]中给B放入jj个线段,(k,i](k,i]这段里的所有线段都给A;要么在区间[0,k][0,k]中给B放入j−num[j][k]j-num[j][k]个线段,(k,i](k,i]这段里的所有线段都给B)
然后就要求一个g[i][j]g[i][j],g[i][j]=[i,j]g[i][j]=[i,j]区间内的所有线段必须选,使得A和B中保含线段少的那个集合里的线段个数最多多少。
g[i][j]=maxx,y∈[0,n]{min{x+y,pre[i][x]+num[i][j]+suf[j][y]}}g[i][j]=\max_{x,y\in[0,n]}\{\min \{x+y,pre[i][x]+num[i][j]+suf[j][y]\}\}
令
fx,y=min{x+y,pre[i][x]+num[i][j]+suf[j][y]}f_{x,y}=\min \{x+y,pre[i][x]+num[i][j]+suf[j][y]\}
xx是[i,j][i,j]左边放入B中的线段个数,yy是[i,j][i,j]右边放入B中的线段个数
在xx固定的情况下,fx,y随yf_{x,y}随y递增呈单凸特点,因此可以利用这一性质,维护两个指针x,yx,y,遍历xx,对于每个xx,可以在期望复杂度O(1)O(1)时间内,移动指针yy并快速找到使得当前的fx,yf_{x,y}最大的yy。
代码
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <algorithm> #define MAXN 410 #define INF 0x3f3f3f3f using namespace std; struct Segment { int L,R; }seg[MAXN*2]; int stack[MAXN*2],top=0,n; int pre[MAXN][MAXN],suf[MAXN][MAXN],g[MAXN][MAXN]; int num[MAXN][MAXN]; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d%d",&seg[i].L,&seg[i].R); seg[i].R+=seg[i].L; //!!!! stack[top++]=seg[i].L; stack[top++]=seg[i].R; } sort(stack,stack+top); top=unique(stack,stack+top)-stack; for(int i=1;i<=n;i++) { seg[i].L=lower_bound(stack,stack+top,seg[i].L)-stack; seg[i].R=lower_bound(stack,stack+top,seg[i].R)-stack; } for(int i=0;i<top;i++) //预处理出num[i][i]~num[i][top] { for(int j=1;j<=n;j++) //!!!!! if(seg[j].L>=i) num[i][seg[j].R]++; for(int j=i+1;j<top;j++) //!!!!! num[i][j]+=num[i][j-1]; } memset(pre,~INF,sizeof(pre)); memset(suf,~INF,sizeof(suf)); pre[0][0]=0; suf[top-1][0]=0; for(int i=0;i<top;i++) { for(int j=0;j<=n;j++) if(pre[i][j]>~INF) pre[i][pre[i][j]]=max(pre[i][pre[i][j]],j); for(int j=n-1;j>=0;j--) pre[i][j]=max(pre[i][j],pre[i][j+1]); for(int j=0;j<=n;j++) for(int k=i+1;k<top;k++) //向后递推,[0,i]里给A放入j个区间,那么用[0,k]里在B中放入pre[i][j]个区间,在A中放入j+num[i][k]个区间的方案更新答案 if(pre[i][j]>~INF) pre[k][pre[i][j]]=max(pre[k][pre[i][j]],j+num[i][k]); } for(int i=top-1;i>=0;i--) { for(int j=0;j<=n;j++) if(suf[i][j]>~INF) suf[i][suf[i][j]]=max(suf[i][suf[i][j]],j); for(int j=n-1;j>=0;j--) suf[i][j]=max(suf[i][j],suf[i][j+1]); for(int j=0;j<=n;j++) for(int k=i-1;k>=0;k--) //向前递推,[i,INF)里给A放入j个区间,那么用[k,INF)里在B中放入suf[i][j]个区间,在A中放入j+num[k][i]个区间的方案来更新答案 if(suf[i][j]>~INF) suf[k][suf[i][j]]=max(suf[k][suf[i][j]],j+num[k][i]); } for(int i=0;i<top;i++) //求g[i][j]=必须使用[i,j]内的区间 for(int j=i;j<top;j++) { g[i][j]=~INF; for(int x=0,y=n;x<=n;x++) { while(y>=0&&x+y>num[i][j]+pre[i][x]+suf[j][y]) y--; //x=[0,i]中B选择的区间个数,y=[j,INF)中B选择的区间个数 if(y>=0) g[i][j]=max(g[i][j],x+y); } } int ans=0; for(int i=0;i<=n;i++) ans=max(ans,min(i,suf[0][i])); printf("%d\n",ans); for(int i=1;i<=n;i++) //!!!! { ans=0; for(int j=0;j<=seg[i].L;j++) for(int k=seg[i].R;k<top;k++) ans=max(ans,g[j][k]); printf("%d\n",ans); } return 0; }
相关文章推荐
- [BZOJ2436][Noi2011]Noi嘉年华(dp)
- bzoj 2436: [Noi2011]Noi嘉年华 (dp)
- [BZOJ]2436 [NOI2011] Noi嘉年华 DP
- 【bzoj 2436】[Noi2011] Noi嘉年华 (dp)
- BZOJ 2436 Noi嘉年华(优化DP)
- 【BZOJ 2436】 2436: [Noi2011]Noi嘉年华 (区间DP)
- BZOJ2436 [Noi2011]Noi嘉年华 【dp】
- BZOJ2436: [Noi2011]Noi嘉年华
- BZOJ 2436 NOI嘉年华(单调优化)
- 2436: [Noi2011]Noi嘉年华 - BZOJ
- BZOJ 2436 Noi嘉年华 (dp)
- bzoj 2436: [Noi2011]Noi嘉年华
- bzoj3963[WF2011]MachineWorks cdq分治+斜率优化dp
- bzoj2435: [Noi2011]道路修建 树上dp
- bzoj3672 [ NOI2014 ] -- 树上CDQ分治 + 斜率优化DP
- [线段树优化 DP] BZOJ 3242 [Noi2013]快餐店
- BZOJ 1499 [NOI2005] 瑰丽华尔兹 | 单调队列优化DP
- bzoj 2442: [Usaco2011 Open]修剪草坪 单调队列优化dp
- [BZOJ 3963][WF2011]MachineWorks:CDQ分治|DP斜率优化
- BZOJ 2435 [Noi 2011] 树DP 解题报告