首先拆这个方差
然后转为斜率优化
然后就是水题了。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
inline void read(long long &x){
x=0;
int f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
x*=f;
}
const long long N=400000;
const long long INF=1e17;
long long n,m;
long long sum[N]={0};
long long f[2][N]={0};
long long a[N]={0};
long long q[N]={0};
int head=0;
int tail=0;
double slope(long long a,long long b,long long cur){
return ((double)f[cur][a]-(double)f[cur][b]+(double)sum[a]*(double)sum[a]-(double)sum[b]*(double)sum[b])/((double)sum[a]-(double)sum[b]);
}
int main(){
read(n);
read(m);
// scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
read(a[i]);
// scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
for(long long i=1;i<=n;i++){
f[0][i]=INF;
}
for(long long i=1;i<=m;i++){
long long cur=i%2;
memset(f[cur],0,sizeof(f[cur]));
head=0;
tail=0;
q[tail]=0;
for(long long j=1;j<=n;j++){
while(head<tail&&slope(q[head+1],q[head],cur^1)<2*sum[j])head++;
// cout<<q[head]<<" ";
f[cur][j]=f[cur^1][q[head]]+(long long)(sum[j]-sum[q[head]])*(sum[j]-sum[q[head]]);
// cout<<f[cur^1][q[head]]<<" ";
while(head<tail&&slope(q[tail],q[tail-1],cur^1)>slope(q[tail],j,cur^1))tail--;
tail++;
q[tail]=j;
}
// cout<<endl;
}
cout<<(long long)f[m%2][n]*m-(long long)sum[n]*sum[n];
}

本文详细介绍了如何通过斜率优化技巧解决一类动态规划问题。利用斜率优化可以将复杂度从O(n^2)降低到O(nlogn),具体方法包括拆解方差并将其转化为斜率形式进行优化。
332

被折叠的 条评论
为什么被折叠?



