bzoj3675: [Apio2014]序列分割

题目链接

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; 
} 
posted @ 2018-06-26 19:58  zzzzx  阅读(95)  评论(0编辑  收藏  举报