BZOJ 2436 NOI嘉年华(单调优化)
2016-06-23 11:49
204 查看
http://www.lydsy.com/JudgeOnline/problem.php?id=2436
题意:两个会场不能同时表演,但是同一个时间可以同时表演,要求让两个会场表演数量最小的最大,然后限制某一个必须表演,最小的要最大是多少。。
思路:先将时间离散化,预处理数组num[i][j],代表时间i到时间j一共包含了几个表演。
然后进行dp,pre[i][j],代表1~时间i,会场A表演了j个,此时会场B最多能表演几个。
pre[i][j]=max(pre[i][j+1],pre[k][j]+num[k][i],pre[k][j-num[k][i]]) 后两个分别代表这个区间的表演放到B,和这个区间的表演放到A,
suf[i][j]代表i~时间m,会场A表演了j个,此时会场B最多能表演几个,这个就是同理了
然后第一问的答案就是max(min(i,pre[m][i]))
对于第二问,我们考虑这样设计:
ans[i][j]=max(min(x+y+num[i][j],pre[i][x]+suf[j][y]))
这样的转移是n^4的,不能通过全部数据。
我们考虑令i和j固定,f[x][y]=min(x+y+num[i][j],pre[i][x]+suf[j][y])
再令x固定,y逐渐增大,发现f[x][y]是单峰的!,因此当f[x][y+1]<f[x][y]就可以break了。
原因是x+y+num[i][j]中只有y是在不断增大的,而pre[i][x]+suf[j][y]中suf[j][y]是不断减小的,由于是取min
因此会有一个瞬间x+y+num[i][j]和pre[i][x]+suf[j][y]会达到最接近,然后此时就是最大的答案,之前的和之后的都不是最优的!
题意:两个会场不能同时表演,但是同一个时间可以同时表演,要求让两个会场表演数量最小的最大,然后限制某一个必须表演,最小的要最大是多少。。
思路:先将时间离散化,预处理数组num[i][j],代表时间i到时间j一共包含了几个表演。
然后进行dp,pre[i][j],代表1~时间i,会场A表演了j个,此时会场B最多能表演几个。
pre[i][j]=max(pre[i][j+1],pre[k][j]+num[k][i],pre[k][j-num[k][i]]) 后两个分别代表这个区间的表演放到B,和这个区间的表演放到A,
suf[i][j]代表i~时间m,会场A表演了j个,此时会场B最多能表演几个,这个就是同理了
然后第一问的答案就是max(min(i,pre[m][i]))
对于第二问,我们考虑这样设计:
ans[i][j]=max(min(x+y+num[i][j],pre[i][x]+suf[j][y]))
这样的转移是n^4的,不能通过全部数据。
我们考虑令i和j固定,f[x][y]=min(x+y+num[i][j],pre[i][x]+suf[j][y])
再令x固定,y逐渐增大,发现f[x][y]是单峰的!,因此当f[x][y+1]<f[x][y]就可以break了。
原因是x+y+num[i][j]中只有y是在不断增大的,而pre[i][x]+suf[j][y]中suf[j][y]是不断减小的,由于是取min
因此会有一个瞬间x+y+num[i][j]和pre[i][x]+suf[j][y]会达到最接近,然后此时就是最大的答案,之前的和之后的都不是最优的!
#include<cstdio> #include<cmath> #include<iostream> #include<cstring> #include<algorithm> struct node{ int s,e; }a[200005]; int p[200005],ans[505][505],n,suf[505][505],pre[505][505],num[505][505]; int read(){ int t=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();} while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} return t*f; } int find(int x){ int l=1,r=p[0]; while (l<=r){ int mid=(l+r)>>1; if (p[mid]==x) return mid; else if (p[mid]<x) l=mid+1; else r=mid-1; } return 0; } void init(){ n=read(); for (int i=1;i<=n;i++) a[i].s=read(),a[i].e=read()+a[i].s,p[++p[0]]=a[i].s,p[++p[0]]=a[i].e; std::sort(p+1,p+1+p[0]); int j=1; for (int i=2;i<=p[0];i++) if (p[i]!=p[j]) p[++j]=p[i]; p[0]=j; for (int i=1;i<=n;i++) a[i].s=find(a[i].s),a[i].e=find(a[i].e); for (int i=1;i<=p[0];i++) for (int j=i;j<=p[0];j++) for (int k=1;k<=n;k++) if (i<=a[k].s&&a[k].e<=j) num[i][j]++; } void dp(){ for (int i=0;i<=500;i++) for (int j=0;j<=500;j++) pre[i][j]=suf[i][j]=-1000000000; pre[0][0]=suf[p[0]+1][0]=0; for (int i=1;i<=p[0];i++) for (int k=i;k>=0;k--){ pre[i][k]=pre[i][k+1]; for (int j=0;j<=i-1;j++) pre[i][k]=std::max(pre[i][k],std::max(pre[j][k]+num[j][i],pre[j][k-num[j][i]])); } for (int i=p[0];i>=1;i--) for (int k=p[0]-i+1;k>=0;k--){ suf[i][k]=suf[i][k+1]; for (int j=i+1;j<=p[0]+1;j++) suf[i][k]=std::max(suf[i][k],std::max(suf[j][k]+num[i][j],suf[j][k-num[i][j]])); } for (int i=1;i<=p[0];i++) for (int j=i;j<=p[0];j++){ int k=1+p[0]-j; for (int x=0;x<=i;x++) for (int y=0;y<=k;y++) if (x+y<=n){ int sx=std::min(x+y+num[i][j],pre[i][x]+suf[j][y]); if (sx<0) break; if (ans[i][j]<sx){ ans[i][j]=sx; }else break; }else break; } } void Output(){ int Ans=0; for (int i=1;i<=n;i++) Ans=std::max(std::min(pre[p[0]][i],i),Ans); printf("%d\n",Ans); for (int i=1;i<=n;i++){ Ans=0; for (int j=1;j<=p[0];j++) for (int k=j;k<=p[0];k++) if (j<=a[i].s&&a[i].e<=k) Ans=std::max(Ans,ans[j][k]); printf("%d\n",Ans); } } int main(){ init(); dp(); Output(); }
相关文章推荐
- 初级程序的日常
- 设计模式 观察者模式 以微信公众服务为例
- QNX车机底层操作系统技术解读
- main函数执行前后--全局构造和atexit
- linux 修改时间并永久生效
- java开发就业信息管理系统
- Android user模式下使用Screencast虚拟控制界面权限修改
- ALS(Alternating Least Squares) 交替最小二乘法概述
- 火狐浏览器下载文件名为乱码
- 无需弹页的新增页面
- 将PDF文件中的表格转换成Excel怎么转换
- 设计模式:创建型模式
- Android中Fragment之间的跳转和数据的传递
- java 解析xml是报编码异常处理方法
- HttpClient使用详解
- 编译dubbo2.5.4时遇到的问题及解决
- optimizer hints
- 浪潮之巅阅读笔记三
- AVInputFormat结构体
- 20150503字符串实战