【BZOJ2436】NOI嘉年华(动态规划)

题面

BZOJ

题解

考虑第一问如何求解

发现状态与选择了哪些活动无关,只与时间有关

设\(f[i][j]\)表示前\(i\)个单位时间(离散后),一个嘉年华选择了\(j\)个活动时

另外一个可以选择的最多的活动数量

转移的话枚举一下转移过来的时间\(k\)

考虑时间\([k..i]\)的活动分配给哪个嘉年华就好了

所以\(f[i][j]=max(f[k][j]+sum[k][i],f[k][j-sum[k][i]])\)

其中\(sum[i][j]\)表示时间\([i,j]\)中能够进行的所有活动的数量。

时间复杂度\(O(n^3)\)

考虑第二问

显然是中间一段强制选,然后剩下的地方被拆成了两段

然后考虑最大值。

注意,这强制选的一段不一定恰好是当前必须选的活动的这一段时间

而是可以向两边拓展

所以我们需要先预处理\(dp[i][j]\)表示时间\([i,j]\)的所有活动必须选择的最优值

设\(g[i][j]\)和\(f\)表示相同的含义,但是时间不是\([1,i]\)而是\([i,n]\),即倒着选。

枚举前面和后面分割出来的时间某个嘉年华分别选择了几个活动,

这样很容易转移,相当于是把中间强制选择的那段时间的所有活动直接加给活动较少的那个嘉年华。

但是这样的复杂度是\(O(n^4)\)的。

我们需要优化这个转移,假设枚举选择了多少个活动的那个嘉年华

在强制选择的区间的前面选了\(x\)个活动,后面选了\(y\)个活动

发现当\(x\)增大时,另外一个嘉年华能够选择的个数会减小,

而中间强制选择的区间的值不会变化,如果继续增加\(y\)的话,发现另外一个嘉年华能够选择的值也会更小,所以\(x\)增加时,\(y\)减少。

这样子可以利用单调性优化掉一个\(n\),时间复杂度变为\(O(n^3)\)。

每次回答询问的时候,确定当前强制选择的活动左右端点,暴力向左右拓展就好了。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 444
inline int read()
{
RG int x=0,t=1;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
int L[MAX],R[MAX],S[MAX],tot,num[MAX][MAX];
int f[MAX][MAX],g[MAX][MAX],d[MAX][MAX],ans,n;
void cmax(int &x,int y){if(x<y)x=y;}
int Calc(int i,int j,int x,int y)
{
if(f[i][x]<0||g[j][y]<0)return -1e9;
int t=f[i][x]+g[j][y];
return min(max(t,x+y),min(t,x+y)+num[i][j]);
}
int main()
{
n=read();
for(int i=1;i<=n;++i)L[i]=read(),R[i]=read()+L[i];
for(int i=1;i<=n;++i)S[++tot]=L[i],S[++tot]=R[i];
sort(&S[1],&S[tot+1]);tot=unique(&S[1],&S[tot+1])-S-1;
for(int i=1;i<=n;++i)L[i]=lower_bound(&S[1],&S[tot+1],L[i])-S;
for(int i=1;i<=n;++i)R[i]=lower_bound(&S[1],&S[tot+1],R[i])-S;
for(int i=0;i<=tot+1;++i)
for(int j=i;j<=tot+1;++j)
for(int k=1;k<=n;++k)
if(i<=L[k]&&R[k]<=j)++num[i][j];
memset(f,-63,sizeof(f));f[0][0]=0;
for(int i=1;i<=tot;++i)
for(int j=0;j<=n;++j)
for(int k=0;k<i;++k)
{
cmax(f[i][j],f[k][j]+num[k][i]);
if(j>=num[k][j])cmax(f[i][j],f[k][j-num[k][i]]);
}
for(int i=1;i<=tot;++i)ans=max(ans,min(i,f[tot][i]));
printf("%d\n",ans);
memset(g,-63,sizeof(g));g[tot+1][0]=0;
for(int i=tot;i;--i)
for(int j=0;j<=n;++j)
for(int k=i+1;k<=tot+1;++k)
{
cmax(g[i][j],g[k][j]+num[i][k]);
if(j>=num[k][j])cmax(g[i][j],g[k][j-num[i][k]]);
}
for(int i=1;i<=tot;++i)
for(int j=i;j<=tot;++j)
if(num[i][j])
{
int y=n;
for(int x=0;x<=n;++x)
{
int nw=Calc(i,j,x,y);
while(y)
{
int nt=Calc(i,j,x,y-1);
if(nw<=nt)--y,nw=nt;
else break;
}
d[i][j]=max(d[i][j],nw);
}
}
for(int i=1;i<=n;++i)
{
ans=0;
for(int j=1;j<=L[i];++j)
for(int k=R[i];k<=tot;++k)
ans=max(ans,d[j][k]);
printf("%d\n",ans);
}
return 0;
}

最新文章

  1. 如何让{dede:channel}有子栏目显示子栏目,无子栏目不显示同级栏目
  2. java 小程序-- 汉诺塔
  3. 【leetcode】Binary Tree Postorder Traversal (hard) ☆
  4. 我们应该如何去了解JavaScript引擎的工作原理
  5. windows中的程序放在linux上因为字符集不同出错
  6. petapoco IsNew
  7. IOS 开发的官方文档链接
  8. 转 velocity 模板使用总结
  9. 关于Rotation和Quaternion的一些问题
  10. 【转载】svn代码回滚命令
  11. Bootstrap_表单_表单控件状态
  12. timesetevent与timekillevent的用法
  13. oracle数据库的编码
  14. angular2 学习笔记 ( Rxjs, Promise, Async/Await 的区别 )
  15. 关于npm的坑
  16. verilog语法实例学习(12)
  17. 前端项目中使用git来做分支和合并分支,管理生产版本
  18. React Native 基础报错及解决方案记录
  19. jmeter 发送http请求,并把获取到的请求的订单信息保存到文件中
  20. 安装Tomcat配置环境变量

热门文章

  1. abp core版本添加额外应用层
  2. .net mvc 使用ueditor的开发(官网没有net版本?)
  3. selenium自动化之加载浏览器的配置文件
  4. MySQL5.6.14从安装到启动全过程
  5. 英特尔&#174; 实感™ 前置摄像头 SR300 和 F200 的比较
  6. 利用Pillow给图片添加重点框(适用UI自动化测试)
  7. spring-boot Jpa配置
  8. Spark SQL、DataFrame和Dataset——转载
  9. ncnblogs.com的用户体验
  10. 软件工程团队项目第一个Sprint评论