zoukankan      html  css  js  c++  java
  • BZOJ 3675: [Apio2014]序列分割

    Description

    将一个序列切割(k)次,每次切割的收益是两边和的乘积,求最大收益.(nleqslant 1 imes 10^5,kleqslant 200)

    Solution

    斜率优化DP..

    因为什么((a+b)c+ab=a(b+c)+bc)..

    所以他是只与结果有关的,跟切割方法无关,随便切就行...

    (f[i][j]=max{f[k][j-1]+s[k](s[i]-s[k])})

    斜率正好是前缀和,并且单调不降..

    所以直接斜率优化那一套就行了...

    Code

    /**************************************************************
        Problem: 3675
        User: BeiYu
        Language: C++
        Result: Accepted
        Time:14596 ms
        Memory:84112 kb
    ****************************************************************/
     
    #include <bits/stdc++.h>
    using namespace std;
     
    typedef long long LL;
    const int N = 100005;
    const int M = 205;
     
    inline int in(int x=0,char ch=getchar()) { while(ch>'9'||ch<'0') ch=getchar();
        while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();return x; }
     
    int n,k;
    int a[N],q[M][N],h[M],t[M];
    LL s[N],f[N][2];
     
    //#define B(i,j) (f[i][(j)&1]-s[i]*s[i])
    //#define F(k,i,j) (B(k,((j)^1))+s[k]*s[i])
     
    inline LL B(int i,int j) { return f[i][j&1]-s[i]*s[i]; }
    inline LL F(int k,int i,int j) { return B(k,j^1)+s[k]*s[i]; }
     
    int main() {
    //  cout<<(sizeof(f)+sizeof(q)+sizeof(s)+sizeof(a))/1024.0/1024.0<<endl;
        n=in(),k=in();k++;
        for(int i=1;i<=n;i++) a[i]=in();
        for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
         
        for(int j=1;j<=k;j++) h[j]=1;
    //  q[0][h[0]=t[0]=1]=0;
    //  for(int i=1;i<=n;i++) f[i][1]=s[i];
        for(int j=2;j<=k;j++) {  
            q[j-1][h[j-1]=t[j-1]=1]=j-1;
            for(int i=j;i<=n;i++) {
                while(h[j-1]<t[j-1] && F(q[j-1][h[j-1]],i,j)<F(q[j-1][h[j-1]+1],i,j)) h[j-1]++;
                f[i][j&1]=F(q[j-1][h[j-1]],i,j);
    //          cout<<i<<" "<<j<<" "<<q[j-1][h[j-1]]<<endl;
                while(h[j-1]<t[j-1] && 
                    (s[q[j-1][t[j-1]]]-s[q[j-1][t[j-1]-1]])*(B(q[j-1][t[j-1]-1],j-1)-B(i,j-1))
                    <=(s[i]-s[q[j-1][t[j-1]-1]])*(B(q[j-1][t[j-1]-1],j-1)-B(q[j-1][t[j-1]],j-1)))
                        t[j-1]--;
                q[j-1][++t[j-1]]=i;
            }
        }
    //  for(int j=0;j<=1;j++) for(int i=1;i<=n;i++) printf("%lld%c",f[i][j]," 
    "[i==n]);
        printf("%lld
    ",f[n][k&1]);
        return 0;
    }
    

      

  • 相关阅读:
    【转】嵌入式软件:C语言编码规范
    【转】如何建立编码规范?
    RAS使用拨号网络拨号的类
    UDP 通讯代码
    【转】heap与stack的区别
    关于textarea在safari chrome下可拖动大小的问题
    Java网络编程入门
    诺基亚发布了它的第一台android手机,x和x+机型
    Spring学习笔记之入门(二)
    Spring学习笔记之入门(一)
  • 原文地址:https://www.cnblogs.com/beiyuoi/p/6728597.html
Copyright © 2011-2022 走看看