• 征途


    虽然又是一遍AC的,但不得不说这题打得我好慌张,还调了十几分钟,虽然都是智障错误。

    回归正题。猛然一看,n只有3000,貌似不要斜率优化耶。

    但事实上,普通DP是N^2*M的,所以还是得斜率优化哈哈。

    构造数列A1~Am,表示第i段的和。

    方差乘m^2后长这样子:m*Ai^2-(Ai)^2

    惊喜的发现(Ai)^2是个定值,那么我们只要使Ai^2最小即可。

    就问你眼不眼熟?这不就是例一吗?但是此题多一维。

    可以推导出状转方程:f[i][j]=min{f[k][j-1]+(sum[i]-sum[k])^2}

    发现f[……][i]只跟f[……][i-1]有关,那就队列里放i-1的然后统计i的答案呗。

    看代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int maxn=3000+10;
    int n,m,f[maxn][maxn],sum[maxn],d[maxn],q[maxn];
    int yval(int a,int b,int c){
        return f[b][c]+sum[b]*sum[b]-f[a][c]-sum[a]*sum[a];
    }
    int xval(int a,int b){return sum[b]-sum[a];}
    signed main(){
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            scanf("%lld",&d[i]);
            sum[i]=sum[i-1]+d[i];
        }
        //memset(f,0x3f,sizeof(f));
        for(int i=1;i<=n;i++)
            f[i][1]=sum[i]*sum[i];
        for(int i=2;i<=m;i++){
            int l=1,r=1;
            q[l]=0;
            for(int j=1;j<=n;j++){
                while(l<r&&yval(q[l],q[l+1],i-1)<=xval(q[l],q[l+1])*2*sum[j])l++;
                f[j][i]=f[q[l]][i-1]+(sum[j]-sum[q[l]])*(sum[j]-sum[q[l]]);
                //printf("%d %d %d %d %d
    ",j,i,q[l],f[q[l]][i-1],f[j][i]);
                while(l<r&&yval(q[r-1],q[r],i-1)*xval(q[r],j)>=xval(q[r-1],q[r])*yval(q[r],j,i-1))r--;
                q[++r]=j;
                //printf("%d %d
    ",l,r);
            }
        }
        //for(int i=1;i<=m;i++)
        //    for(int j=1;j<=n;j++)
        //        printf("f[%d][%d]=%d
    ",j,i,f[j][i]);
        printf("%lld
    ",m*f[n][m]-sum[n]*sum[n]);    
        return 0;
    } 

    看到那一堆调试代码了吗?警醒读者:别把i和j弄反了!!!

  • 相关阅读:
    后端返回文件流 前端处理方法
    证书profile 申请
    uniapp 报错 签名不对 请检查签名是否与开放平台上填写的一致
    微信开放平台创建应用如何填写官网
    防抖和节流笔记二
    防抖和节流笔记一
    如何申请ios证书
    textarea 固定大小,滚动条,限制拖动,文字对齐
    根据角色获取用户组
    号码验证
  • 原文地址:https://www.cnblogs.com/syzf2222/p/12386827.html
Copyright © 2020-2023  润新知