bzoj3675: [Apio2014]序列分割
题目链接
题解
可以发现,答案与分割的顺序无关,只与切在哪有关
分割的每一块,都要保证与其他的乘一次球和,注意不要重复
那么dp方程就是
\(dp[k][i]=dp[k-1][j]+(sum[i]-sum[j])*sum[j]\)
对于割的次数那维滚掉
对于第二维斜率优化
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
inline int read() {
int x = 0,f = 1;
char c = getchar();
while(c < '0' || c > '9')c = getchar();
while(c <= '9' && c >= '0')x = x * 10 + c - '0',c = getchar();
return x * f;
}
int n,K;
const int maxn = 100007;
long long dp[maxn] , q[maxn] , g[maxn],sum[maxn],a[maxn];
inline double X(int x) {return 1.0 * sum[x];}
inline double Y(int x) {return 1.0 * g[x] - sum[x] * sum[x];}
double slop(int i,int j) {
if(sum[i] == sum[j]) return 0;
return (Y(i) - Y(j)) / (X(i) - X(j));
}
int main() {
n = read(),K = read();
for(int i = 1;i <= n;++ i) a[i] = read();
for(int i = 1;i <= n;++ i) sum[i] = sum[i - 1] + a[i];
for(int l,r,k = 2;k <= K + 1;++ k) {
l = r = 0;
for(int i = k - 1;i <= n;++ i) {
while(l < r && slop(q[l + 1],q[l]) > -sum[i]) l ++;
dp[i] = g[q[l]] + sum[q[l]] * (sum[i] - sum[q[l]]);
while(l < r && slop(q[r - 1],q[r]) < slop(q[r],i)) r --;
q[++ r] = i;
}
for(int j = k - 1;j <= n;++ j) g[j] = dp[j];
}
printf("%lld\n",dp[n]);
return 0;
}