• BZOJ3675 [Apio2014]序列分割[斜率优化dp]


    好久没写题解了惹,主要去省选玩了一趟之后就补文化课了,oi忘得差不多了。。

    所以众所周知,这个人又来切水题了。

    地址


    发现题中划分是无序的,不利于dp。是否可以从左到右依次划分?然后发现不管我过程中怎么划分,顺序是什么,只要最终划分的块都一样,那价值肯定一样,因为对于最终每一块,他在过程中每次被划开时,和被划开的另一大块中每一个最终的小块都产生了一次价值,所以最终一个划分价值就是各个小块的和相互的乘积的和,也就是$sumlimits_{i=1}^{k} sumlimits_{j=1}^{i-1} sum_i*sum_j$。

    所以就可以dp,设划分$k$块,目前到$i$,当前划分出来的新的一块与先前每一块都产生一次价值,即可算作这一块与先前整块产生的价值,$f[k][i]=max{f[k-1][j]+(sum[i]-sum[j])*sum[j]}$。

    然后拆开来就是一个斜截式,于是上斜率优化,由于$f$太大会爆空间,所以滚动一下。没了。

    不知道我为什么常数巨大,可能是我太菜了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #define dbg(x) cerr<<#x<<" = "<<x<<endl
    #define _dbg(x,y) cerr<<#x<<" = "<<x<<"   "<<#y<<" = "<<y<<endl
    using namespace std;
    typedef long long ll;
    template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;}
    template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;}
    template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    template<typename T>inline T read(T&x){
        x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
        while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    }
    const int N=100000+7,M=200+5;
    ll f[2][N],sum[N];
    int q[N];//int g[N][M];
    int n,m,l,r;
    inline ll Y(int j,int p){return f[p^1][j]-sum[j]*sum[j];}
    inline ll X(int j){return sum[j];}
    
    int main(){//freopen("test.in","r",stdin);//freopen("test.out","w",stdout);
        read(n),read(m);++m;
        for(register int i=1;i<=n;++i)read(sum[i]),sum[i]+=sum[i-1];
        for(register int k=2,p=1;k<=m;++k,p^=1){
            q[l=r=1]=k-1;memset(f[p],0,sizeof f[p]);
            for(register int i=k;i<=n;++i){
                while(l<r&&Y(q[l+1],p)-Y(q[l],p)>=-sum[i]*(X(q[l+1])-X(q[l])))++l;
                f[p][i]=f[p^1][q[l]]+(sum[i]-sum[q[l]])*sum[q[l]];//g[i][k]=q[l];
                while(l<r&&(Y(q[r],p)-Y(q[r-1],p))*(X(i)-X(q[r]))<=(Y(i,p)-Y(q[r],p))*(X(q[r])-X(q[r-1])))--r;
                q[++r]=i;
            }
        }
        printf("%lld
    ",f[!(m&1)][n]);
    //  int tmp=g[n][m],k=m-1;
    //  while(tmp)printf("%d ",tmp),tmp=g[tmp][k--];
    //  puts("");
        return 0;
    }
  • 相关阅读:
    String.trim()这个细节不能忘记
    Integer.parseInt(f.trim())中String f要加trim()
    类属性不能写在try{}catch(){}里面
    011--TypeScript泛型
    010--TypeScript里面的this和重载
    009--函数(基本实例和函数类型)
    007--TypeScript之类的修饰符
    008--TypeScript存储器和静态属性
    006--TypeScript之类
    005--TypeScript接口
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/10886044.html
Copyright © 2020-2023  润新知