[BZOJ 3675][APIO 2014]序列分割(斜率优化DP)
来源:互联网 发布:java 并发编程的书 编辑:程序博客网 时间:2024/05/16 05:17
题目链接
http://www.lydsy.com/JudgeOnline/problem.php?id=3675
思路
这题不是很难,但是坑了我一个下午+半个晚上才做出来,郁闷
首先设
很容易推出DP方程:
这个DP复杂度是
然后看看能不能优化一下,发现这个DP其实很像一个斜率优化DP,可以通过优化来降低一维复杂度,变成大约是
假设在DP到
再设
这玩意长得挺像斜率的。。。上面的不等式左边当然是越大越好,因此最终我们需要维护一个上凸壳,每次决策时首先将那些队首肯定不能充当最优解,而且以后也不能的元素都弹出队列,然后用当前的队首去更新
咦。。。好像原题中是要求输出一个最大方案的(看来BZOJ的管理员太懒不愿意造第二问数据2333),这个就记录下DP的前驱就好了
后记:
1、最好不要直接写斜率的表达式,因为如果分母是0那么就会出问题,最好把分母移到不等式的另一边去
2、每次决策的2次出队过程必须时刻保证队列中至少有2个元素。
代码
第一次做的,没带读入优化,整整10s
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <algorithm>#define MAXN 100010#define EPS 1e-6#define INF 1000000000using namespace std;typedef long long int LL;int n,m,h,t,q[MAXN];LL f[MAXN][2],sum[MAXN],y[MAXN][2]; //f[i][j]=长度为i的序列,一共划分了j次得到的最大分数int now=0; //now=当前用的下标int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%lld",&sum[i]); sum[i]+=sum[i-1]; } for(int i=1;i<=n;i++) y[i][0]=sum[i]*sum[i]; for(int j=1;j<=m;j++) //划分j次 { now=1-now; h=1,t=1; q[h]=0; for(int i=1;i<=n;i++) //长度为i的序列划分j次 { while(h<t&&sum[i]*(sum[q[h+1]]-sum[q[h]])>=(y[q[h+1]][1-now]-y[q[h]][1-now])) h++; f[i][now]=f[q[h]][1-now]+sum[i]*sum[q[h]]-sum[q[h]]*sum[q[h]]; y[i][now]=sum[i]*sum[i]-f[i][now]; while(h<t&&(y[q[t]][1-now]-y[q[t-1]][1-now])*(sum[i]-sum[q[t]])>=(y[i][1-now]-y[q[t]][1-now])*(sum[q[t]]-sum[q[t-1]])) t--; q[++t]=i; } } printf("%lld\n",f[n][now]); return 0;}
第二次加入了读入优化,略微快了几百毫秒
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <algorithm>#define MAXN 100010#define EPS 1e-6#define INF 1000000000using namespace std;typedef long long int LL;int n,m,h,t,q[MAXN];LL f[MAXN][2],sum[MAXN],y[MAXN][2]; //f[i][j]=长度为i的序列,一共划分了j次得到的最大分数,y[i][t]=sum[i]*sum[i]-f[i][t]int now=0; //now=当前用的下标inline LL read(){ LL ans=0; char ch=getchar(); while(ch==' '||ch=='\n') ch=getchar(); while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar(); return ans;}int main(){ n=(int)read(),m=(int)read(); for(int i=1;i<=n;i++) { sum[i]=read(); sum[i]+=sum[i-1]; } for(int i=1;i<=n;i++) y[i][0]=sum[i]*sum[i]; for(int j=1;j<=m;j++) //划分j次 { now=1-now; h=1,t=1; q[h]=0; for(int i=1;i<=n;i++) //长度为i的序列划分j次 { while(h<t&&sum[i]*(sum[q[h+1]]-sum[q[h]])>=(y[q[h+1]][1-now]-y[q[h]][1-now])) h++; f[i][now]=f[q[h]][1-now]+sum[i]*sum[q[h]]-sum[q[h]]*sum[q[h]]; y[i][now]=sum[i]*sum[i]-f[i][now]; while(h<t&&(y[q[t]][1-now]-y[q[t-1]][1-now])*(sum[i]-sum[q[t]])>=(y[i][1-now]-y[q[t]][1-now])*(sum[q[t]]-sum[q[t-1]])) t--; q[++t]=i; } } printf("%lld\n",f[n][now]); return 0;}
- [BZOJ 3675][APIO 2014]序列分割(斜率优化DP)
- [省选前题目整理][BZOJ 3675][APIO 2014]序列分割(斜率优化DP)
- BZOJ 3675 APIO2014 序列分割 斜率优化DP
- [BZOJ 3675][Apio2014]序列分割:DP斜率优化
- bzoj 3675: [Apio2014]序列分割 斜率优化dp
- 【bzoj 3675】序列分割(斜率优化DP)
- 【DP】APIO 2014 序列分割
- 【斜率DP】BZOJ 3675:[Apio2014]序列分割
- BZOJ 3675 APIO2014 序列分割 斜率优化
- bzoj 3675 [Apio2014]序列分割 斜率优化
- BZOJ 3675 [Apio2014] 序列分割 斜率优化
- 3675: [Apio2014]序列分割 斜率优化DP
- BZOJ 1911 APIO 2010 特别行动队 斜率优化DP
- bzoj 3675: [Apio2014]序列分割(斜率优化)
- bzoj 3675 [Apio2014]序列分割(斜率优化)
- BZOJ 3675 [Apio2014]序列分割 动态规划+斜率优化
- [APIO2014]序列分割(斜率优化dp)
- BZOJ3675 [Apio2014]序列分割 【斜率优化dp】
- Swing 外观框架 BeautyEye 使用
- 解释器模式
- 安卓paint path常用属性
- 屁股决定脑袋
- linux系统间传输文件
- [BZOJ 3675][APIO 2014]序列分割(斜率优化DP)
- UVA 10163 - Storage Keepers(dp)
- 迭代器
- 关于一些博弈的模型总结,巴什博奕+威佐夫博奕+尼姆博奕+Fibonacci博弈+公平组合博弈。把网上 的一些资料总结了一下
- KindEditor 编辑器之简易使用
- 3-6月份学习计划
- uva 10280 Old Wine Into New Bottles (有剪枝的完全背包)
- “教育培训类网站”_简要需求分析
- OC_ 语言BLOCK和协议