• bzoj4518 [ SDOI2016 ] --斜率优化DP


    设x[i]为第i天走的路程,s为路程总和,则:

    ans=[(s/m-x[1])^2+(s/m-x[2])^2+(s/m-x[3])^2+...+(s/m-x[m])^2]*m

         =[(s-x[1]*m)^2+(s-x[2]*m)^2+(s-x[3]*m)^2]+...+(s-x[m]*m)^2)]/m

         =s^2+m*(x[1]^2+x[2]^2+x[3]^2+...+x[m]^2)-2*(x[1]+x[2]+x[3]+...+x[m])*s

         =m*(x[1]^2+x[2]^2+x[3]^2+...+x[m]^2)-s^2

    由于m,s不变,问题可以转化为将一个长为n的序列划分成m段,求最小平方和

    令f[i][j]为将长为j的序列划分成i段的最小平方和,则

    f[i][j]=min(f[i][k]+(sum[j]-sum[k])^2),0<k<j

    很明显的斜率优化。

    斜率优化过程如下:

    设p<k<j,在求f[i][j]时k比p优,于是可得如下方程:
    f[i-1][k]+(sum[j]-sum[k])^2<f[i-1][p]+(sum[j]-sum[p])^2

    f[i-1][k]+sum[k]^2-(f[i-1][p]+sum[p]^2)<2*(sum[k]-sum[p])*sum[j]

    (f[i-1][k]+sum[k]^2-(f[i-1][p]+sum[p]^2))/(2*sum[k]-2*sum[p])<sum[j]

    如果令y[i-1][t]=f[i-1][t]+sum[t]^2,x[i-1][t]=2*sum[t],

    则原式可化为:(y[i-1][k]-y[i-1][p])/(x[i-1][k]-x[i-1][p])<sum[j],不就是线段kp的斜率小于sum[j]吗?

    令g[i][j](i>j)为线段ij的斜率。

    于是在求f[i]时维护一个序列,满足对任意j(j>2),g[j][j-1]>g[j-1][j-2],则f[i][j]的最优值就从序列中斜率小于sum[j]的序号最大的线段的右端点转移。

    时间复杂度从O(n*n*m)降到O(n*m)

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define ll long long
    ll i,j,k,n,m,f[3001][3001],x[3001],y[3001][3001],sum[3001],s,l,r,q[3001];
    int main()
    {
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++)scanf("%lld",&sum[i]),s+=sum[i],sum[i]+=sum[i-1],x[i]=sum[i]<<1,f[1][i]=sum[i]*sum[i],y[1][i]=f[1][i]<<1;
        for(i=2;i<=m;i++){
            l=r=0;
            for(j=1;j<=n;j++){
                while(l<r&&y[i-1][q[l+1]]-y[i-1][q[l]]<=sum[j]*(x[q[l+1]]-x[q[l]]))l++;
                f[i][j]=f[i-1][q[l]]+(sum[j]-sum[q[l]])*(sum[j]-sum[q[l]]);
                y[i][j]=f[i][j]+sum[j]*sum[j];
                while(l<r&&(x[q[r]]-x[q[r-1]])*(y[i-1][j]-y[i-1][q[r-1]])<=(x[j]-x[q[r-1]])*(y[i-1][q[r]]-y[i-1][q[r-1]]))r--;
                q[++r]=j;
            }
        }
        printf("%lld
    ",f[m][n]*m-s*s);
        return 0;
    }
    bzoj4518
  • 相关阅读:
    react 中cookie的使用
    使用react-router-dom 来搭建react路由
    取消浏览器的自动缓存
    vue 的$nextTick方法,与$set()方法
    vue监听data以及prop中的参数变化
    iview树的修改某个节点,树刷新后自动展开你刚才展开的所有节点
    Linux vim常用命令
    Linux yum源配置
    博客园鼠标点击特效
    Linux 简介
  • 原文地址:https://www.cnblogs.com/gjghfd/p/5997938.html
Copyright © 2020-2023  润新知