题目大意
题解
(g(L,R)=sum_{i=L}^{R}sum_{j=i+1}^{R}val[i] imes val[j]=frac{1}{2}left(sum_{i=L}^{R}sum_{j=L}^{R}val[i] imes val[j]-sum_{i=L}^R val[i]^2
ight))
(=frac{1}{2}left(left(sum_{i=L}^R val[i]
ight)^2-sum_{i=L}^R val[i]^2
ight))
记 (s[n]=sum_{i=1}^{n} val[i]), (s2[n]=sum_{i=1}^n val[i]^2),
则 (g(L,R)=frac{1}{2}left(left(s[R]-s[L-1]
ight)^2-left(s2[R]-s2[L-1]
ight)
ight))
设 (dp[i][j]) 表示前 (i) 个仓库,炸毁 (j) 条铁路的最小价值,
则有 (dp[i][j]=min{dp[k][j-1]+g(k+1,i)},k<i)。
将 (g(k+1,i)=frac{1}{2}left(left(s[i]-s[k]
ight)^2-left(s2[i]-s2[k]
ight)
ight)) 代入状态转移方程,
有 (dp[i][j]=dp[k][j-1]+frac{1}{2}left(left(s[i]-s[k]
ight)^2-left(s2[i]-s2[k]
ight)
ight)),
整理可得,(2dp[k][j-1]+s[k]^2+s2[k]=2s[i]s[k]+2dp[i][j]+s2[i]-s[i]^2)。
不妨令 (y=2dp[k][j-1]+s[k]^2+s2[k],K=2s[i],x=s[k]),
则原式等于 (y=Kx+2dp[i][j]+s2[i]-s[i]^2),
发现斜率 (K=2s[i]) 单调递增,显然可以斜率优化,使用单调队列维护一个下凸壳。
时间复杂度 (O(nm)) 。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
using namespace std;
#define RG register int
#define LL long long
template<typename elemType>
inline void Read(elemType &T){
elemType X=0,w=0; char ch=0;
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
T=(w?-X:X);
}
LL Value[1005],dp[1005][1005];
LL s[1005],s2[1005];
int Q[1005];
int N,M,head,tail;
inline LL y(int j,int k){return (dp[k][j-1]<<1)+s[k]*s[k]+s2[k];}
inline LL x(int k){return s[k];}
inline LL K(int i){return s[i]<<1;}
inline LL g(int L,int R){return ((s[R]-s[L-1])*(s[R]-s[L-1])-(s2[R]-s2[L-1]))>>1;}
inline void maintain(int i,int j,int k){dp[i][j]=dp[k][j-1]+g(k+1,i);}
LL Solve(){
memset(dp,0x3f,sizeof(dp));
for(RG i=1;i<=N;++i)
dp[i][0]=g(1,i);
for(RG j=1;j<=M;++j){
dp[j][j]=0;
head=1;tail=0;
Q[++tail]=j;
for(RG i=j+1;i<=N;++i){
while(tail-head+1>=2){
int a=Q[head],b=Q[head+1];
if(y(j,b)-y(j,a)<=K(i)*(x(b)-x(a))) ++head;
else break;
}
maintain(i,j,Q[head]);
while(tail-head+1>=2){
int a=Q[tail-1],b=Q[tail];
if((y(j,b)-y(j,a))*(x(i)-x(a))>=(y(j,i)-y(j,a))*(x(b)-x(a))) --tail;
else break;
}
Q[++tail]=i;
}
}
return dp[N][M];
}
int main(){
while(~scanf("%d%d",&N,&M)){
if(N==0 || M==0) break;
for(RG i=1;i<=N;++i){
Read(Value[i]);
s[i]=s[i-1]+Value[i];
s2[i]=s2[i-1]+Value[i]*Value[i];
}
printf("%lld
",Solve());
}
return 0;
}