BZOJ4518:征途(dp+斜率优化)

我最近总是在省选题中找noip题做…

题面

题意:给你一排n个数,让你分成m组,每组是连续的一段,求每段和的最小方差,乘以m^2后输出。n≤3000。

在学斜率优化的时候我记得某位大佬提到了方差,所以就开始画柿子吧,设sum为n个数的和, xi 为第i段的和。

ans=mi=1m(xisumm)2

然后…
ans=mi=1mx2isum2

变成了最小化这玩意 mi=1x2i ,就是个裸斜率优化了。

#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))

typedef long long LL;

const int N=3030;

int n,m;
int g[N],a[N],sum[N],q[N],y[N],f[N];

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i];

    for(int i=1;i<=n;i++)
    g[i]=sum[i]*sum[i],y[i]=g[i]*2;

    for(int j=2;j<=m;j++)
    {
        int hh=1,tt=1;
        q[1]=j-1;
        for(int i=j;i<=n;i++)
        {
            while(hh<tt&&y[q[hh+1]]-y[q[hh]]<=2*sum[i]*(sum[q[hh+1]]-sum[q[hh]]))
            hh++;
            int hy=q[hh];
            f[i]=g[hy]+(sum[i]-sum[hy])*(sum[i]-sum[hy]);

            y[i]=g[i]+sum[i]*sum[i];

            while(hh<tt&&(y[i]-y[q[tt]])*(sum[q[tt]]-sum[q[tt-1]])<=(y[q[tt]]-y[q[tt-1]])*(sum[i]-sum[q[tt]]))
            tt--;
            q[++tt]=i;
        }

        for(int i=1;i<=n;i++)
        g[i]=f[i];
    }

    cout<<m*g[n]-sum[n]*sum[n]<<endl;

    return 0;
}

这里写图片描述
在我这个oi蒟蒻眼里,这只是一个发生在身边,却从未涉足的浪漫小故事。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值