zoukankan      html  css  js  c++  java
  • 【洛谷3648】[APIO2014] 序列分割(斜率优化DP)

    点此看题面

    大致题意: 你可以对一个序列进行(k)次分割,每次得分为两个块元素和的乘积,求总得分的最大值。

    区间(DPor)斜率优化(DP)

    这题目第一眼看上去感觉很明显是区间(DP)

    但是,一看数据范围,(nle100000),这是要上天的节奏!

    不过,再看(mle200),比较显然应该是(O(nm))的时间复杂度。

    实际上,这题的确是可以用斜率优化(DP)来做到(O(nm))的。

    推性质

    首先,我们要知道一个性质:将一个区间进行若干次分割,分割的顺序是不影响最后的总得分的

    证明如下:

    设要对一个区间进行(2)次分割,则分割完后有(3)个区间,每个区间的价值和分别为(a_1,a_2,a_3)

    则总共有两种分割顺序,得到的总得分分别为(a_1·(a_2+a_3)+a_2·a_3)((a_1+a_2)·a_3+a_1·a_2)

    实际上,这两个式子化简后皆为(a_1a_2+a_1a_3+a_2a_3)

    而多次分割其实是同理的。

    状态转移

    这样一来,就不难想到针对这种问题的常见套路:设(f_{i,j})表示在前(i)个数中割(j)次得到的最大总得分

    状态转移方程如下:

    [f_{i,j}=f_{x,j-1}+sum_x*(sum_i-sum_x) ]

    这应该是比较好理解的吧,就相当于枚举一个割的位置,总得分为该区间前半部分割(j-1)次的最大得分加上这两部分元素和的乘积

    对于这种式子,比较显然可以斜率优化

    将原式展开得:

    [f_{x,j-1}-sum_x*sum_x=-sum_x*sum_i+f_{i,j} ]

    要注意在转移过程中可能会出现分母为(0)的情况,则需要给此时的斜率赋值为(-INF)

    由于要记方案,所以再用一个(g)数组记录下从哪个元素转移而来即可。

    代码

    #include<bits/stdc++.h>
    #define max(x,y) ((x)>(y)?(x):(y))
    #define min(x,y) ((x)<(y)?(x):(y))
    #define Gmax(x,y) (x<(y)&&(x=(y)))
    #define Gmin(x,y) (x>(y)&&(x=(y))) 
    #define abs(x) ((x)<0?-(x):(x))
    #define swap(x,y) (x^=y^=x^=y)
    #define uint unsigned int
    #define LL long long
    #define ull unsigned long long
    #define INF 1e18
    #define N 100000
    #define M 200
    using namespace std;
    int n,m,sum[N+5];
    class Class_FIO
    {
        private:
            #define Fsize 100000
            #define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,Fsize,stdin),A==B)?EOF:*A++)
            #define pc(ch) (void)(FoutSize<Fsize?Fout[FoutSize++]=ch:(fwrite(Fout,1,FoutSize,stdout),Fout[(FoutSize=0)++]=ch))
            int f,FoutSize,Top;char ch,Fin[Fsize],*A,*B,Fout[Fsize],Stack[Fsize];
        public:
            Class_FIO() {A=B=Fin;}
            inline void read(int &x) {x=0,f=1;while(!isdigit(ch=tc())) f=ch^'-'?1:-1;while(x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));x*=f;}
            inline void read_digit(int &x) {while(!isdigit(x=tc()));x&=15;}
            inline void readc(char &x) {while(isspace(x=tc()));}
            inline void reads(string &x) {x="";while(isspace(ch=tc()));while(x+=ch,!isspace(ch=tc())&&~ch);}
            inline void write(LL x) {if(!x) return pc('0');x<0&&(pc('-'),x=-x);while(x) Stack[++Top]=x%10+48,x/=10;while(Top) pc(Stack[Top--]);}
            inline void writec(char x) {pc(x);}
            inline void writes(string x) {for(register int i=0,len=x.length();i<len;++i) pc(x[i]);}
            inline void clear() {fwrite(Fout,1,FoutSize,stdout),FoutSize=0;}
    }F;
    class Class_SlopeDP
    {
        private:
            #define A(x) (f[x][j-1]-1LL*sum[x]*sum[x])
            #define B(x) (-1LL*sum[x])
            #define S(x,y) (B(x)^B(y)?1.0*(A(y)-A(x))/(B(y)-B(x)):-INF)//对于分母为0的情况,返回-INF
            #define Slope (1LL*sum[i])
            int q[N+5],g[N+5][M+5];LL f[N+5][M+5];
            inline void PrintStep(int x,int y) {y&&(PrintStep(g[x][y-1],y-1),F.write(x),F.writec(' '),0);}//输出方案
        public:
            inline void Solve()//DP转移
            {
                register int i,j,H,T;
                for(j=1;j<=m;++j)
                {
                    for(q[H=T=1]=0,i=1;i<=n;++i)//每次记得清空队列
                    {
                        while(H<T&&S(q[H],q[H+1])<=Slope) ++H;
                        f[i][j]=f[g[i][j]=q[H]][j-1]+1LL*sum[q[H]]*(sum[i]-sum[q[H]]);
                        while(H<T&&S(q[T],i)<=S(q[T-1],q[T])) --T;
                        q[++T]=i;
                    }
                }
            }
            inline void Print() {F.write(f[n][m]),F.writec('
    '),PrintStep(g[n][m],m);}
    }SlopeDP;
    int main()
    {
        register int i;
        for(F.read(n),F.read(m),i=1;i<=n;++i) F.read(sum[i]),sum[i]+=sum[i-1];
        return SlopeDP.Solve(),SlopeDP.Print(),F.clear(),0;
    }
    
  • 相关阅读:
    【JavaScript】explode动画
    【JavaScript】插件参数的写法
    【webpack】理解配置文件
    你真的了解盒模型么
    一看看懂Protocol Buffer(协议篇)
    es7你都懂了吗?今天带你了解es7的神器decorator
    快速了解react
    简单聊一聊那些svg的沿路径运动
    转转RN工程化历程
    微信小程序内嵌网页的一些(最佳)实践
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu3648.html
Copyright © 2011-2022 走看看