BZOJ3675: [Apio2014]序列分割

【传送门:BZOJ3675


简要题意:

  一开始给出n个数的一段序列,可以分割k次,每次只能分割一段序列,一段序列被分割后就变成两个序列,每次分割的价值为分割的位置左边的数的和乘右边的数的和

  求出最大价值


题解:

  DP+斜率优化

  首先来设f[i][k]为前i个数,分割k次得到的最大价值

  接下来。。。

  方程。。。。

  方程。。。

  方程。。

  方程。

  需要玄学思考

  其实这里用了乘法分配律,证明分割的顺序是与答案无关的,只要割对地方就行了

  太棒了这样就得到f[i][k]=max(f[j][k-1]+sum[j]*(sum[i]-sum[j]))

  然后滚动数组f[i][now]=max(f[j][last]+sum[j]*(sum[i]-sum[j]))

  再用斜率优化,美滋滋

  设j1<j2<i

  得到

  f[j2][last]+sum[j2]*(sum[i]-sum[j2])>f[j1][last]+sum[j1]*(sum[i]-sum[j1])

  f[j2][last]-f[j1][last]+sum[j1]^2-sum[j2]^2>(sum[j1]-sum[j2])*sum[i]

  (f[j2][last]-f[j1][last]+sum[j1]^2-sum[j2]^2)/(sum[j1]-sum[j2])<sum[i]

  因为sum[j1]-sum[j2]有可能等于0,所以在处理队列的时候,如果存在sum[j1]-sum[j2],要将j1给除掉,保留j2

  注意加long long


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
//f[i][now]=max(f[j][last]+sum[j]*(sum[i]-sum[j]))
//j1<j2<i
//f[j2][last]+sum[j2]*(sum[i]-sum[j2])>f[j1][last]+sum[j1]*(sum[i]-sum[j1])
//f[j2][last]-f[j1][last]+sum[j1]^2-sum[j2]^2>(sum[j1]-sum[j2])*sum[i]
//(f[j2][last]-f[j1][last]+sum[j1]^2-sum[j2]^2)/(sum[j1]-sum[j2])<sum[i]
LL f[110000][2];
LL sum[110000];
int now=1,last=0;
LL slop(int j1,int j2)
{
    return (f[j2][last]-f[j1][last]-sum[j2]*sum[j2]+sum[j1]*sum[j1])/(sum[j1]-sum[j2]);
}
int list[110000];
int main()
{
    int n,K;
    scanf("%d%d",&n,&K);
    sum[0]=0;
    for(int i=1;i<=n;i++)
    {
        int d;
        scanf("%d",&d);
        sum[i]=sum[i-1]+d;
    }
    memset(f,0,sizeof(f));
    for(int k=1;k<=K;k++)
    {
        now^=1;last^=1;
        int head=1,tail=0;list[head]=0;
        for(int i=k;i<=n;i++)
        {
            while(head<tail&&(sum[list[head]]==sum[list[head]+1]||slop(list[head],list[head+1])<sum[i])) head++;
            int j=list[head];
            f[i][now]=f[j][last]+sum[j]*(sum[i]-sum[j]);
            while(head<tail&&(sum[i]==sum[list[tail]]||slop(list[tail-1],list[tail])>slop(list[tail],i))) tail--;
            list[++tail]=i;
        }
    }
    printf("%lld\n",f[n][now]);
    return 0;
}

 

posted @ 2018-03-15 20:04  Star_Feel  阅读(167)  评论(0编辑  收藏  举报