斜率dp
#include <STDIO.H>
#include <STRING.H>
// 保证不超时,斜率dp
/*
dp[i][x] 前 i 个点,去掉j条边所获破坏的最大值
res = tol - dp[i][x]
dp[i][x] = max( dp[j][x-1] + sum[j]*(sum[i]-sum[j])) x-1 < j < i
斜率dp:
sum[i]递增
if k<j, dp[j][x-1] >= dp[k][x-1]
dp[k][x-1] + sum[k]*(sum[i]-sum[k]) <= dp[j][x-1] + sum[j]*(sum[i]-sum[j])
then
(sum[j]*sum[j] - dp[j][x-1]) - (sum[k]*sum[k] - dp[k][x-1]) <= sum[i]*(sum[j] - sum[k])
if aj = (sum[j]*sum[j] - dp[j][x-1])
bj = sum[j]
sum[i] 值不变
then
d(k,j) = (aj-ak)/(bj-bk)
结论:
1. 若d(k,j)>d(j,i) 则排除j
2. 若d(j,i)<sum[i] 排除 j
*/
const int MAXN = 1005;
int n, m;
int sum[MAXN];
int a[MAXN];
int dp[MAXN][MAXN];
int tol;
int q[MAXN];
int DP(int i, int x, int j)
{
return dp[j][x-1] + sum[j]*(sum[i]-sum[j]);
}
int uDP(int k, int j, int x)
{
return sum[j]*sum[j] - dp[j][x-1] - sum[k]*sum[k] + dp[k][x-1];
}
int dDP(int k, int j)
{
return sum[j] - sum[k];
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
while (scanf("%d%d", &n, &m) == 2 && (n+m))
{
int i;
sum[0] = 0;
for (i = 1; i<= n; ++i)
{
scanf("%d", &a[i]);
sum[i] = sum[i-1]+a[i];
}
tol = 0;
for (i = n; i>0; --i)
tol += a[i]*sum[i-1];
memset(dp, 0, sizeof dp);
int head, tail;
for (int x = 1; x <= m; x++)
{
head = tail = 0;
q[tail++] = x;
for ( i = x+1; i<= n; ++i)
{
// 2.
while (tail-head>1 && uDP(q[head],q[head+1],x) <= sum[i]*dDP(q[head],q[head+1]))
++head;
dp[i][x] = DP(i,x,q[head]);
// 1.
while (tail-head>1 && uDP(q[tail-2],q[tail-1],x)*dDP(q[tail-1],i)
>=uDP(q[tail-1],i,x)*dDP(q[tail-2],q[tail-1]))
tail--;
q[tail++] = i;
}
}
printf("%d\n", tol-dp[n][m]);
}
return 0;
}