[斜率优化dp] HDU 2829 Lawrence

题目大意

传送门

题解

\(g(L,R)=\sum_{i=L}^{R}\sum_{j=i+1}^{R}val[i]\times val[j]=\frac{1}{2}\left(\sum_{i=L}^{R}\sum_{j=L}^{R}val[i]\times val[j]-\sum_{i=L}^R val[i]^2\right)\)
\(=\frac{1}{2}\left(\left(\sum_{i=L}^R val[i]\right)^2-\sum_{i=L}^R val[i]^2\right)\)
\(s[n]=\sum_{i=1}^{n} val[i]\)\(s2[n]=\sum_{i=1}^n val[i]^2\)
\(g(L,R)=\frac{1}{2}\left(\left(s[R]-s[L-1]\right)^2-\left(s2[R]-s2[L-1]\right)\right)\)

\(dp[i][j]\) 表示前 \(i\) 个仓库,炸毁 \(j\) 条铁路的最小价值,
则有 \(dp[i][j]=\min\{dp[k][j-1]+g(k+1,i)\},k<i\)

\(g(k+1,i)=\frac{1}{2}\left(\left(s[i]-s[k]\right)^2-\left(s2[i]-s2[k]\right)\right)\) 代入状态转移方程,
\(dp[i][j]=dp[k][j-1]+\frac{1}{2}\left(\left(s[i]-s[k]\right)^2-\left(s2[i]-s2[k]\right)\right)\)
整理可得,\(2dp[k][j-1]+s[k]^2+s2[k]=2s[i]s[k]+2dp[i][j]+s2[i]-s[i]^2\)
不妨令 \(y=2dp[k][j-1]+s[k]^2+s2[k],K=2s[i],x=s[k]\)
则原式等于 \(y=Kx+2dp[i][j]+s2[i]-s[i]^2\)
发现斜率 \(K=2s[i]\) 单调递增,显然可以斜率优化,使用单调队列维护一个下凸壳。
时间复杂度 \(O(nm)\)

Code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
using namespace std;

#define RG register int
#define LL long long

template<typename elemType>
inline void Read(elemType &T){
    elemType X=0,w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    T=(w?-X:X);
}

LL Value[1005],dp[1005][1005];
LL s[1005],s2[1005];
int Q[1005];
int N,M,head,tail;

inline LL y(int j,int k){return (dp[k][j-1]<<1)+s[k]*s[k]+s2[k];}
inline LL x(int k){return s[k];}
inline LL K(int i){return s[i]<<1;}
inline LL g(int L,int R){return ((s[R]-s[L-1])*(s[R]-s[L-1])-(s2[R]-s2[L-1]))>>1;}
inline void maintain(int i,int j,int k){dp[i][j]=dp[k][j-1]+g(k+1,i);}

LL Solve(){
    memset(dp,0x3f,sizeof(dp));
    for(RG i=1;i<=N;++i)
        dp[i][0]=g(1,i);
    for(RG j=1;j<=M;++j){
        dp[j][j]=0;
        head=1;tail=0;
        Q[++tail]=j;
        for(RG i=j+1;i<=N;++i){
            while(tail-head+1>=2){
                int a=Q[head],b=Q[head+1];
                if(y(j,b)-y(j,a)<=K(i)*(x(b)-x(a))) ++head;
                else break;
            }
            maintain(i,j,Q[head]);
            while(tail-head+1>=2){
                int a=Q[tail-1],b=Q[tail];
                if((y(j,b)-y(j,a))*(x(i)-x(a))>=(y(j,i)-y(j,a))*(x(b)-x(a))) --tail;
                else break;
            }
            Q[++tail]=i;
        }
    }
    return dp[N][M];
}

int main(){
    while(~scanf("%d%d",&N,&M)){
        if(N==0 || M==0) break;
        for(RG i=1;i<=N;++i){
            Read(Value[i]);
            s[i]=s[i-1]+Value[i];
            s2[i]=s2[i-1]+Value[i]*Value[i];
        }
        printf("%lld\n",Solve());
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/AEMShana/p/13376890.html