zoukankan      html  css  js  c++  java
  • 斜率优化DP

    pengzhou讲完之后留了几道题......

    [HNOI2008]玩具装箱toy

    bzoj 1010 传送门

    洛谷P3195 传送门

    设c[i]是题目中c[i]的前缀和。

    手推一下状态转移方程,f[i]=f[k]+(i-k-1+c[i]-c[k]-L)^2

    搞一搞,x[k]=k+c[k],y[k]=f[k]+(k+c[k]+l+1)^2

    这道题斜率单调递增,用队列维护下凸包即可。

     1 #include<cstdio>
     2 #define ll long long
     3 
     4 int n,tk=1,pt=1;
     5 ll l;
     6 ll c[50005];
     7 ll f[50005];
     8 ll q[50005];
     9 
    10 ll y(int p)
    11 {
    12     return (ll)(f[p]+(ll)(p+c[p]+l+1)*(ll)(p+c[p]+l+1));
    13 }
    14 
    15 ll x(int p)
    16 {
    17     return (ll)(p+c[p]);
    18 }
    19 
    20 int main()
    21 {
    22     scanf("%d%lld",&n,&l);
    23     for(int i=1;i<=n;i++)scanf("%lld",&c[i]),c[i]+=c[i-1];
    24     for(int i=1;i<=n;i++)
    25     {
    26         while(tk<pt&&y(q[tk+1])-y(q[tk])<=2ll*(x(i))*(x(q[tk+1])-x(q[tk])))q[tk++]=0;
    27         f[i]=f[q[tk]]+((ll)(i-q[tk]-1)+c[i]-c[q[tk]]-l)*((ll)(i-q[tk]-1)+c[i]-c[q[tk]]-l);
    28         while(tk<pt&&(y(q[pt])-y(i))*(x(q[pt-1])-x(q[pt]))<=(y(q[pt-1])-y(q[pt]))*(x(q[pt])-x(i)))q[pt--]=0;
    29         q[++pt]=i;
    30     }
    31     printf("%lld",f[n]);
    32 }
    玩具装箱toy

    [APIO2010]特别行动队

    bzoj 1911 传送门

    洛谷P3628 传送门

    和上一道差不多。

    设s[i]为士兵战斗力的前缀和。 

    (f[i]-a*si^2-b*si-c)=(f[j]+a*sj^2-b*sj)-(si)*(2*a*sj)

    b=y-kx

    b=f[i]-a*si^2-b*si-c,y=f[j]+a*sj^2-b*sj,k=si,x=2*a*sj

    发现斜率k递增,x递减。

    用队列维护上凸包即可。

     1 #include<cstdio>
     2 #define ll long long
     3 
     4 int n;
     5 ll a,b,c;
     6 ll s[1000005];
     7 ll f[1000005];
     8 int q[1000005],tl=1,hd=1; 
     9 
    10 ll y(int p)
    11 {
    12     return f[p]+a*s[p]*s[p]-b*s[p];
    13 }
    14 
    15 ll x(int p)
    16 {
    17     return 2ll*a*s[p];
    18 }
    19 
    20 int main()
    21 {
    22     scanf("%d%lld%lld%lld",&n,&a,&b,&c);
    23     for(int i=1;i<=n;i++)scanf("%lld",&s[i]),s[i]+=s[i-1];
    24     for(int i=1;i<=n;i++)
    25     {
    26         while(hd<tl&&y(q[hd])-y(q[hd+1])<=s[i]*(x(q[hd])-x(q[hd+1])))hd++;
    27         f[i]=f[q[hd]]+a*(s[i]-s[q[hd]])*(s[i]-s[q[hd]])+b*(s[i]-s[q[hd]])+c;
    28         while(hd<tl&&(y(q[tl-1])-y(q[tl]))*(x(q[tl])-x(i))>=(y(q[tl])-y(i))*(x(q[tl-1])-x(q[tl])))tl--;
    29         q[++tl]=i;
    30     }
    31     printf("%lld",f[n]);
    32     return 0;
    33 }
    特别行动队

    [SDOI2016]征途

    bzoj 4518 传送门

    洛谷P4072 传送门

    套路都是相似的呀~

    这个多了一个维度,不慌。

    显然先搞出来一个前缀和。

    拿方差公式搞一搞,发现如果有某一天走了xi这么远,对方差的贡献为m*xi^2-2*xi*s[n]

    而且无论怎么走,对方差的贡献都是在s[n]^2的基础上往上加的。

    设f[i][j]为第j天走到第i个时候的贡献。

    f[i][j]=f[k][j-1]+m(s[i]-s[k])^2-2*(s[i]-s[k])*s[n]

    发现更新第j天的时候需要第j-1天的答案。

    所以第一个循环枚举第几天,里面的循环枚举到了第几个。

    斜率优化一下:

    (f[i][j]+2*s[n]*s[i]-m*s[i]^2) = (f[k][j-1]+2*s[n]*s[k]+m*s[k]^2) - (s[i]) * (2*m*s[k])

    b=y-k*x

    用队列维护下凸包。

    计算第j天的时候,把第j-1天的答案推到队列里。

    注意计算第一天答案的时候不能更新队列。

    第一天无论走到哪,都必须是从0走过来的。

    所以必须保证计算第一天答案的时候队列里只有0。

     1 #include<cstdio>
     2 #define ll long long
     3 
     4 int n,t;
     5 ll m;
     6 ll s[3005];
     7 ll f[3005][3005];
     8 int q[3005],hd,tl;
     9 
    10 ll x(int p)
    11 {
    12     return 2ll*m*s[p];
    13 }
    14 
    15 ll y(ll p)
    16 {
    17     return f[p][t-1]+2ll*s[n]*s[p]+m*s[p]*s[p];
    18 }
    19 
    20 int main()
    21 {
    22     scanf("%d%lld",&n,&m);
    23     for(int i=1;i<=n;i++)scanf("%lld",&s[i]),s[i]+=s[i-1];
    24     for(t=1;t<=m;t++)
    25     {
    26         hd=tl=1;
    27         q[1]=0;
    28         for(int i=1;i<=n;i++)
    29         {
    30             while(hd<tl&&y(q[hd+1])-y(q[hd])<=s[i]*(x(q[hd+1])-x(q[hd])))hd++;
    31             f[i][t]=y(q[hd])-s[i]*x(q[hd])+m*s[i]*s[i]-2ll*s[i]*s[n];
    32             while(hd<tl&&(y(i)-y(q[tl]))*(x(q[tl])-x(q[tl-1]))<=(y(q[tl])-y(q[tl-1]))*(x(i)-x(q[tl])))tl--;
    33             if(t>1)q[++tl]=i;
    34         }
    35     }
    36     printf("%lld",f[n][m]+s[n]*s[n]);
    37     return 0;
    38 }
    征途
  • 相关阅读:
    python 文件和路径操作函数小结
    python文件处理
    jquery操作select
    ubuntu 安装ODOO时的python的依赖
    XML-RPC 实现C++和C#交互
    C#接收xmlrpc接口返回哈希表格式
    XmlRpc with C#/Java【转】
    OpenERP 的XML-RPC的轻度体验+many2many,one2many,many2one创建方式
    在Ubuntu Server上源码安装OpenERP 8.0,并配置wsgi和nginx运行环境
    C# 文件与二进制互转数据库写入读出
  • 原文地址:https://www.cnblogs.com/eternhope/p/9630340.html
Copyright © 2011-2022 走看看