[HDU2829] Lawrence
[HDU2829] Lawrence
题意简析
定义一个序列的价值:序列中任意两个元素的积之和。
给定义一个长度为n的序列,可以从中间断开m次,求如何断开,使得产生的多段序列的价值和最小。
这种分段问题的单调性都比较明显
\(dp[i][j]\)表示当前分到第\(i\)个点,分了\(j\)段的方案
对于\(dp[i][j]\)的决策,\(j\)越大,决策点越大(分的段数越多,每段就越小)
对于每个\(i\)进行一次决策单调性分治求解,复杂度$n^2 \ log \ n $
const int N=1010;
const ll INF=1ll<<50;
int n,m;
ll a[N],dp[N][N];
int s[N],qs[N];
void Solve(int p,int l,int r,int L,int R) {
if(l>r) return;
int mid=(l+r)>>1;
ll mi=INF;
int id=L;
rep(i,L,R) {
ll x=dp[i-1][mid-1]+1ll*(s[p]-s[i-1])*(s[p]-s[i-1])-(qs[p]-qs[i-1]);
if(x<mi) mi=x,id=i;
}
dp[p][mid]=mi;
Solve(p,l,mid-1,L,id);
Solve(p,mid+1,r,id,R);
}
int main() {
while(~scanf("%d %d",&n,&m) && n) {
m++;
rep(i,1,n) {
a[i]=rd();
s[i]=s[i-1]+a[i];
qs[i]=qs[i-1]+a[i]*a[i];
}
memset(dp,63,sizeof dp);
dp[0][0]=0;
rep(i,1,n) Solve(i,1,min((int)i,m),1,i);
printf("%lld\n",dp[n][m]/2);
}
}
\[\
\]
\[\
\]