首先这道题有一个结论:确定了每次切割的位置之后,最终的得分与切割的顺序无关。
可以设确定了这
k
个切割位置之后分成的
[1,y]
的得分为
∑1≤i<j≤hxixj
[y+1,n]
的得分为
∑h+1≤i<j≤k+1xixj
(可以考虑在
[1,y]
和
[y+1,n]
内都按照位置顺序进行切割)
而第一次切割的得分为
∑hi=1xi
乘以
∑k+1i=h+1xi
。
这时候就很容易得出,上面的结论成立。
并且得分为
∑1≤i<j≤k+1xixj
。
观察这个式子,进行一下变形,得到:
得分
=(∑k+1i=1xi)2−∑k+1i=1x2i2
这样,问题转化成了求
∑k+1i=1x2i
的最小值。
这样就和Sdoi2016 Day2 T3的征途那道题一样了,具体见:
http://blog.csdn.net//xyz32768/article/details/78385734
代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
typedef long long ll;
const int N = 1e5 + 5, M = 205;
int n, K, a[N], H, T, que[N];
ll sum[N], f[N], g[N], X[N], Y[N];
bool slope(int p1, int p2, int p3) {
ll x1 = (Y[p1] - Y[p2]) * (X[p2] - X[p3]),
x2 = (Y[p2] - Y[p3]) * (X[p1] - X[p2]);
return x1 >= x2;
}
ll calc(int j, int i) {
return Y[j] - X[j] * sum[i];
}
int main() {
int i, j; n = read(); K = read();
for (i = 1; i <= n; i++) sum[i] = sum[i - 1] + (a[i] = read());
for (i = 1; i <= n; i++) f[i] = sum[i] * sum[i];
for (j = 2; j <= K + 1; j++) {
H = 1; que[T = 1] = j - 1; X[j - 1] = sum[j - 1] * 2;
Y[j - 1] = f[j - 1] + sum[j - 1] * sum[j - 1];
for (i = j; i <= n; i++) {
while (H < T && calc(que[H], i) >= calc(que[H + 1], i)) H++;
g[i] = f[i]; f[i] = calc(que[H], i) + sum[i] * sum[i];
X[i] = sum[i] * 2; Y[i] = g[i] + sum[i] * sum[i];
while (H < T && slope(que[T - 1], que[T], i)) T--;
que[++T] = i;
}
}
cout << (sum[n] * sum[n] - f[n] >> 1) << endl;
return 0;
}