• bzoj1010玩具装箱 斜率优化dp


    显然f[i]=min(f[j]+(sum[i]-sum[j]+i-(j+1)-l)^2)

    sum[i]表示前缀和

    但显然这样的时间复杂度无法得满分,于是我们考虑斜率优化。

    为了方便书写,令sum[i]=sum[i]+i,l=l+1

    方程变为f[i]=min(f[j]+(sum[i]-sum[j]-l)^2)

    当k状态对于当前i比j状态更优时(k>j),f[k]+(sum[i]-sum[k]-l)^2<f[j]+(sum[i]-sum[j]-l)^2

    通过数学推理,可以得到f[j]+sum[j]*sum[j]-f[k]-sum[k]*sum[k]/(2*(sum[j]-sum[k])<sum[i]-l

    我们令不等式左边为K(j,k)

    若K(i,j)>K(j,k)则j状态在之后一定不是最优状态。

    证明:假设之后一状态w

    1.K(j,k)<sum[w]-l,此时k比j优,故j状态不是最优

    2.K(j,k)>=sum[w]-l,由条件可推出K(i,j)>sum[w]-l,此时i比j优。证毕!

    然后就可以用一个单调队列维护k(i,j)

    ac代码

    #include<bits/stdc++.h>
    #define maxn 100005
    #define ll long long 
    using namespace std;
    ll sum[maxn],n,m,f[maxn];
    ll q[maxn];
    double K(ll j,ll k)
    {
    	return (double)(f[j]+sum[j]*sum[j]-f[k]-sum[k]*sum[k])/(2.0*(sum[j]-sum[k]));
    }
    ll read()
    {
    	ll x=0,c;while(!isdigit(c=getchar()));
    	while(x=x*10+c-'0',isdigit(c=getchar()));
    	return x;
    }
    int main()
    {
    	n=read();m=read()+1;
    	for(int i=1;i<=n;i++)sum[i]=sum[i-1]+read();
    	for(int i=1;i<=n;i++)sum[i]+=i;
    	int l=0,r=0;
    	for(int i=1;i<=n;i++)
    	{
    		while(l<r&&K(q[l],q[l+1])<=sum[i]-m)l++;
    		f[i]=f[q[l]]+(sum[i]-sum[q[l]]-m)*(sum[i]-sum[q[l]]-m);
    		while(l<r&&K(q[r-1],q[r])>=K(q[r],i))r--;
    		q[++r]=i;
    	}
    	printf("%lld
    ",f[n]);
    	return 0;
    }
    

      

  • 相关阅读:
    linux: xargs docs
    os:systemctl文档(三)systemd.syntax
    linux:crontab 定时执行任务(整理)
    学习:理解“学习”
    哲学:“理论”的范畴(整理)
    asm:nasm文档
    linux: find docs
    c/cpp:gcc 文档
    os:systemctl文档(一)systemctl
    java~集合分组groupby的实现
  • 原文地址:https://www.cnblogs.com/hlsb/p/8541687.html
Copyright © 2020-2023  润新知