zoukankan      html  css  js  c++  java
  • 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
    ",f[n][now]);
        return 0;
    }

     

  • 相关阅读:
    centos7下升级SSH
    docker: read tcp 192.168.7.235:36512->54.230.212.9:443: read: connection reset by peer.
    Rancher学习笔记----在UI界面添加主机页面无法正常显示
    Rancher3----安装部署rancher
    Rancher2-----了解什么是rancher以及简单部署
    unity坑-编译错误
    游戏UI系统设计
    使用采样器声明
    着色器数据类型和精度
    着色器编译目标等级
  • 原文地址:https://www.cnblogs.com/Never-mind/p/8573276.html
Copyright © 2011-2022 走看看