BZOJ 3675: 序列分割 (斜率优化dp)

Description

小H最近迷上了一个分隔序列的游戏。在这个游戏里,小H需要将一个长度为n的非负整数序列分割成k+1个非空的子序列。为了得到k+1个子序列,小H需要重复k次以下的步骤:
1.小H首先选择一个长度超过1的序列(一开始小H只有一个长度为n的序列——也就是一开始得到的整个序列);
2.选择一个位置,并通过这个位置将这个序列分割成连续的两个非空的新序列。
 
每次进行上述步骤之后,小H将会得到一定的分数。这个分数为两个新序列中元素和的乘积。小H希望选择一种最佳的分割方式,使得k轮之后,小H的总得分最大。
 

Input

输入第一行包含两个整数n,k(k+1≤n)。

第二行包含n个非负整数a1,a2,...,an(0≤ai≤10^4),表示一开始小H得到的序列。

Output

输出第一行包含一个整数,为小H可以得到的最大分数。

Sample Input

7 3
4 1 3 4 0 2 3

Sample Output

108 
题意:给出一个包含n个非负整数的序列,要求将其分割成k+1个序列,每次分割可以获得一定的分数,分数=序列分割位置左侧的数之和×序列分割位置右侧的数之和。要求最大分数是多少。
思路:值得注意的是最后得到的分数与分割的先后顺序无关 所以我们可以大胆的进行划分dp[i][j]表示前i个数分割j次得到的最大分数
dp[i][j]=max(dp[k][j-1]+sum[k]*(sum[i]-sum[k])) 这里略过斜率优化的证明 我们还可以发现 可以用滚动数组降低空间复杂度
细节:斜率分母可能为0 所以要特判一下
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
#define ll long long int
using namespace std;
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
int moth[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int dir[4][2]={1,0 ,0,1 ,-1,0 ,0,-1};
int dirs[8][2]={1,0 ,0,1 ,-1,0 ,0,-1, -1,-1 ,-1,1 ,1,-1 ,1,1};
const int inf=0x3f3f3f3f;
const ll mod=1e9+7;
ll n,k;
ll a[100007];
ll dp[100007][2];
ll sum[100007];
ll q[100007];
double slope(ll j,ll k,ll zu){
    return sum[k]-sum[j]==0?0:((dp[j][zu]-sum[j]*sum[j]-dp[k][zu]+sum[k]*sum[k])
    /(sum[k]-sum[j]));
}
int main(){
    ios::sync_with_stdio(false);
    while(cin>>n>>k){
        for(int i=1;i<=n;i++)
            cin>>a[i],sum[i]=sum[i-1]+a[i];
        int l,r;
        for(int j=1;j<=k;j++){ //分割次数 
            l=r=1;
            for(int i=1;i<=n;i++){ //人数 
                while(l<r&&slope(q[l],q[l+1],(j-1)%2)<sum[i]) l++;
                dp[i][j%2]=dp[q[l]][(j-1)%2]+sum[q[l]]*(sum[i]-sum[q[l]]);
                while(l<r&&slope(q[r-1],q[r],(j-1)%2)>slope(q[r],i,(j-1)%2)) r--;
                q[++r]=i;    
            }
        }
        cout<<dp[n][k%2]<<endl;
    }
    return 0;
}

 

 

posted @ 2019-04-30 19:59  WAKBGAN  阅读(145)  评论(0编辑  收藏  举报