2018.09.29 bzoj3675: [Apio2014]序列分割(斜率優化dp)
阿新 • • 發佈:2018-12-12
傳送門 斜率優化dp經典題目。 首先需要證明只要選擇的K個斷點是相同的,那麼得到的答案也是相同的。 根據分治的思想,我們只需要證明有兩個斷點時成立,就能推出K個斷點時成立。 我們設兩個斷點分成的三段連續序列的和為 如果先分左邊有: 如果先分右邊有: 是相同的。 那麼這樣我們就可以按從左到右劃分斷點的思路來進行dp了。 令為前j個數i個斷點能夠劃分出的最大值。 那麼顯然有: {} {} &&隊頭出隊 => => => 隊尾出隊: 程式碼:
#include<bits/stdc++.h>
#define N 100005
#define ll long long
using namespace std;
inline ll read(){
ll ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
int n,K,hd,tl,q[N],tmp;
ll f[2][N],sum[N];
inline ll calcX(int i,int j){return sum[j]-sum[i];}
inline ll calcY(int i,int j){return (f[tmp^1][i]-sum[i]*sum[i])-(f[tmp^1][j]-sum[j]*sum[j]);}
int main(){
n=read(),K=read(),tmp=0;
for(int i=1;i<=n;++i)sum[i]=sum[i-1]+read();
for(int i=1;i<=K;++i){
hd=tl=1;
for(int j=1;j<=n;++j){
while(hd<tl&&calcY(q[hd],q[hd+1])<=calcX(q[hd],q[hd+1])*sum[j])++hd;
int k=q[hd];
f[tmp][j]=f[tmp^1][k]+sum[k]*(sum[j]-sum[k]);
while(hd<tl&&calcY(q[tl-1],q[tl])*calcX(q[tl],j)>=calcY(q[tl],j)*calcX(q[tl-1],q[tl]))--tl;
q[++tl]=j;
}
tmp^=1;
}
printf("%lld",f[tmp^1][n]);
return 0;
}