Luogu-3648 [APIO2014]序列分割

题目链接

题解:

首先要发现一个重要的性质:分割的顺序是不会影响答案的

证明:

首先对于没有交的两段区间,显然先后顺序改变不会有影响

而对于在同一段区间上的两次分割:

设有一段序列由长度为\(x,y,z\)的三段拼接起来

如果先分割\(xy\)和\(z\),再分割\(x\)和\(y\),答案是\((x+y)*z+x*y\)

而如果先分割\(x\)和\(yz\),再分割\(y\)和\(z\),答案是\(x*(y+z)+y*z\)

可以发现,两个答案都是\(xy+xz+yz\),即分割顺序不影响答案

这样我们就可以愉快地DP啦

设\(f[i][j]\)为将\(1\sim i\)这段分割\(j\)次产生的代价,\(s[i]\)为\(1\sim i\)段的总长,则有:

\[f[i][j]=f[k][j-1]+s[k]*(s[i]-s[k]) \quad k\in [1,i-1]
\]

分割次数这一维可以滚动优化空间,设上一次的为\(g[i]\),这一次要求的是\(f[i]\)

上面的式子就是

\[f[i]=g[k]+s[k]*(s[i]-s[k]) \quad k\in [1,i-1]
\]

哎,感觉很像可以斜率优化的式子啊,那么...

如果从\(k\)转移比从\(j\)转移更优,则:

\[g[k]+s[k]*(s[i]-s[k]) > g[j]+s[j]*(s[i]-s[j])
\]

再化一化

\[\frac{(g[k]+s[k]*s[k])-(g[j]-s[j]*s[j])}{s[j]-s[k]} >s[i]
\]

于是我们就可以用斜率优化dp啦,

注意这题精度卡的简直丧心病狂...算斜率的时候一定要先算减再乘\(1.0\)

代码

#include<map>
#include<queue>
#include<cmath>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
inline ll read(){
ll ans=0,fh=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
ans=(ans<<1)+(ans<<3)+ch-'0',ch=getchar();
return ans*fh;
}
const int maxn=1e5+100;
const long double inf=1e18;
int n,k,st[maxn],tp,pre[210][maxn],q[maxn];
ll s[maxn],f[maxn],g[maxn];
inline long double slope(int x,int y){
if(s[x]==s[y]) return -inf;
long double aa=1.0*((g[x]-s[x]*s[x])-(g[y]-s[y]*s[y]));
return aa/(s[y]-s[x]);
}
int main(){
// freopen("nh.in","r",stdin);
//freopen("zhy.out","w",stdout);
n=read(),k=read();
for(int i=1;i<=n;i++) s[i]=read()+s[i-1];
for(int i=1;i<=k;i++){
int l=1,r=0;q[++r]=0;
for(int j=1;j<=n;j++){
while(l<r&&slope(q[l],q[l+1])<=s[j]) l++;
f[j]=g[q[l]]+s[q[l]]*(s[j]-s[q[l]]);
pre[i][j]=q[l];
while(l<r&&slope(q[r-1],q[r])>=slope(q[r],j)) r--;
q[++r]=j;
}
memcpy(g,f,sizeof(g));
}
printf("%lld\n",g[n]);
for(int i=pre[k][n];i;i=pre[--k][i]) st[++tp]=i;
while(tp) printf("%d ",st[tp--]);
return 0;
}

最新文章

  1. SSI指令
  2. WindowsForm菜单工具栏--2016年12月6日
  3. iOS coredata 级联删除
  4. 【转载】shell中 dd 命令
  5. hdu 2047 阿牛的EOF牛肉串
  6. oracle系列--第一篇 数据库基础
  7. NBUT 1602 Mod Three(线段树单点更新区间查询)
  8. Java遇见HTML——JSP篇之JSP内置对象(下)
  9. poj 1654 Area (多边形求面积)
  10. RT-thread学习笔记(一)
  11. cocos2dx 内存管理机制
  12. iOS KVO的原理
  13. 1.ssh访问限制
  14. CodeForces 711B Chris and Magic Square
  15. css 控制横向布局,超出隐藏,滚动
  16. openstack搭建之-horizon配置(14)
  17. 在 Azure 中管理 Windows 虚拟机的可用性
  18. Zabbix应用三:Zabbix监控MySQL
  19. LACP-链路聚合
  20. 咏南 DATASNAP LINUX中间件

热门文章

  1. 将坐标转化为与X轴正半轴夹角模板
  2. jpa单向一对多关联映射
  3. URAL 2040 Palindromes and Super Abilities 2(回文树)
  4. jquery ajax 传数据到后台乱码的处理方法
  5. 如何看懂ORACLE执行计划
  6. 在Sql Server中使用证书加密数据
  7. ffmpeg命令
  8. 储存应用程序的配置信息ini实现方式
  9. mongoose连接数据库的两种形式
  10. Hibernate缓存原理