[BZOJ2436][Noi2011]Noi嘉年华(dp)
2016-08-17 18:16
465 查看
题目描述
传送门题解
非常神的一道dp题,感觉在考场上想出来是十分困难的。首先对于第一问,先将区间离散,那么所有的时间就都变成O(n)级别的了。可以预处理出sum[i][j]表示时间i~j内有多少个活动。设f[i][j]表示到第i时间为止,第一个场地已经举办了j场活动时第二个场地最多举办多少场活动。
求f的过程可以用一个O(n3)的dp,转移方程为f[i][j]=max{f[i−1][j],f[k][j]+sum[k+1][i],f[k][j−sum[k+1][i]]}
分别表示不举行活动,在二号场地举行活动和在一号场地举行活动。
那么第一问的答案就是max{min(i,f[time][i])}
对于第二问,再用同样的方法求g[i][j]表示倒序时间到i时,第一个场地举办了j个活动时第二个场地最多举办多少个活动。
设dp[i][j]表示i~j这一段所有的活动同时选到某一个场地的最大答案。
显然如果我们必须选的是区间(l,r)
那答案就是max{dp[i][j](i<=x,j>=y)}
dp[i][j]怎么求?
dp[i][j]=max{min(min(x+y,f[i−1][x]+g[j+1][y])+sum[i][j],max(x+y,f[i−1][x]+g[j+1][y]))}。
这样复杂度是O(n4).
考虑如何优化。
我们假设随着x上升时,y也增加,那么显然f[i−1][x]和g[j+1][y]都是不增的。从要使x+y和f[i−1][x]+g[j+1][y],尽量平均的角度考虑,这样的情况是不可能出现的。
所以我们得出了一个结论:随着x上升,在最优处的y值是单调不增的。
时间复杂度可以优化到O(n3).
代码
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> using namespace std; #define N 205 int n,s,t,xx,lsh,ans,inf; int X[N*2],p[N*2],loc[N*2],sum[N*2][N*2],f[N*2] ,g[N*2] ,dp[N*2][N*2]; struct hp{int l,r;}show ; inline int cmp(int a,int b) { return X[a]<X[b]; } inline int get(int i,int j,int x,int y) { if (f[i-1][x]==inf||g[j+1][y]==inf) return inf; return min(min(x+y,f[i-1][x]+g[j+1][y])+sum[i][j],max(x+y,f[i-1][x]+g[j+1][y])); } int main() { scanf("%d",&n); for (int i=1;i<=n;++i) { scanf("%d%d",&s,&t); X[++xx]=s,X[++xx]=s+t-1; } for (int i=1;i<=xx;++i) p[i]=i; sort(p+1,p+xx+1,cmp);X[0]=-1; for (int i=1;i<=xx;++i) if (X[p[i]]!=X[p[i-1]]) loc[p[i]]=++lsh; else loc[p[i]]=lsh; xx=0; for (int i=1;i<=n;++i) show[i].l=loc[++xx],show[i].r=loc[++xx]; for (int i=1;i<=lsh;++i) for (int j=i;j<=lsh;++j) for (int k=1;k<=n;++k) if (show[k].l>=i&&show[k].r<=j) sum[i][j]++; memset(f,128,sizeof(f)); inf=f[0][0]; f[0][0]=0; for (int i=1;i<=lsh;++i) for (int j=0;j<=sum[1][i];++j) { f[i][j]=f[i-1][j]; for (int k=0;k<i;++k) { f[i][j]=max(f[i][j],f[k][j]+sum[k+1][i]); if (j-sum[k+1][i]>=0) f[i][j]=max(f[i][j],f[k][j-sum[k+1][i]]); } } ans=0; for (int i=0;i<=n;++i) ans=max(ans,min(i,f[lsh][i])); printf("%d\n",ans); memset(g,128,sizeof(g)); g[lsh+1][0]=0; for (int i=lsh;i>=1;--i) for (int j=0;j<=n;++j) { g[i][j]=g[i+1][j]; for (int k=lsh+1;k>i;--k) { g[i][j]=max(g[i][j],g[k][j]+sum[i][k-1]); if (j-sum[i][k-1]>=0) g[i][j]=max(g[i][j],g[k][j-sum[i][k-1]]); } } for (int i=1;i<=lsh;++i) for (int j=i;j<=lsh;++j) { int y=n; for (int x=0;x<=n;++x) { int now=get(i,j,x,y); while (y&&now<=(t=get(i,j,x,y-1))){now=t; y--;} dp[i][j]=max(now,dp[i][j]); } } for (int k=1;k<=n;++k) { ans=0; for (int i=1;i<=show[k].l;++i) for (int j=show[k].r;j<=lsh;++j) ans=max(ans,dp[i][j]); printf("%d\n",ans); } }
总结
相关文章推荐
- 【BZOJ 2436】 2436: [Noi2011]Noi嘉年华 (区间DP)
- [BZOJ 2436][NOI 2011]NOI嘉年华(DP优化)
- [BZOJ]2436 [NOI2011] Noi嘉年华 DP
- bzoj 2436: [Noi2011]Noi嘉年华 (dp)
- 【bzoj 2436】[Noi2011] Noi嘉年华 (dp)
- BZOJ2436 [Noi2011]Noi嘉年华 【dp】
- bzoj 2436: [Noi2011]Noi嘉年华
- BZOJ 2436 Noi嘉年华 (dp)
- BZOJ2436: [Noi2011]Noi嘉年华
- BZOJ 2436 Noi嘉年华(优化DP)
- 2436: [Noi2011]Noi嘉年华 - BZOJ
- BZOJ 2435 [Noi 2011] 树DP 解题报告
- bzoj 2435: [Noi2011]道路修建【树形dp】
- BZOJ 2436 NOI嘉年华(单调优化)
- BZOJ2435 [Noi2011]道路修建 【树形Dp 吧。。】
- bzoj2435: [Noi2011]道路修建 树上dp
- BZOJ2435 [Noi2011]道路修建 【树形Dp 吧。。】
- 【BZOJ2435】【Noi2011】道路修建 树形DP
- BZOJ 2436: [Noi2011]Noi嘉年华
- [bzoj2435][Noi2011]道路修建(树上dp)