• bzoj1911[Apio2010]特别行动队 斜率优化dp


    1911: [Apio2010]特别行动队

    Time Limit: 4 Sec  Memory Limit: 64 MB
    Submit: 5057  Solved: 2492
    [Submit][Status][Discuss]

    Description

    Input

    Output

    Sample Input

    4
    -1 10 -20
    2 2 3 4

    Sample Output

    9

    HINT


    dp[i]=dp[j]+a*x*x+b*x+c
    x=sum[i]-sum[j]

    证明单调性
    假设对于i点 k<j且j的决策比k优
    dp[j]+a*(sum[i]-sum[j])*(sum[i]-sum[j])+b*(sum[i]-sum[j])+c>=dp[k]+a*(sum[i]-sum[k])*(sum[i]-sum[k])+b*(sum[i]-sum[k])+c
    化简得 dp[j]+a*sum[j]*sum[j]-2*a*sum[i]*sum[j]-b*sum[j]>=dp[k]+a*sum[k]*sum[k]-2*a*sum[i]*sum[k]-b*sum[k]

    要证明单调性 需证明下面的式子
    dp[j]+a*(sum[t]-sum[j])*(sum[t]-sum[j])+b*(sum[t]-sum[j])+c>=dp[k]+a*(sum[t]-sum[k])*(sum[t]-sum[k])+b*(sum[t]-sum[k])+c
    化简得dp[j]+a*sum[j]*sum[j]-2*a*sum[t]*sum[j]-b*sum[j]>=dp[k]+a*sum[k]*sum[k]-2*a*sum[t]*sum[k]-b*sum[k]

    设t>i 显然sum[t]>=sum[i] 设sum[t]=sum[i]+v
    代入sum[t]得 dp[j]+a*sum[j]*sum[j]-2*a*sum[i]*sum[j]-b*sum[j]+v*sum[j]>=dp[k]+a*sum[k]*sum[k]-2*a*sum[i]*sum[k]-b*sum[k]+v*sum[k]
    因为j>k 所以sum[j]>=k 上式成立,决策单调性得证
    证毕

    可以写出斜率式
    dp[j]+a*sum[j]^2-2*a*sum[i]*sum[j]-b*sum[j]>=dp[k]+a*sum[k]^2-2*a*sum[i]*sum[k]-b*sum[k] 且j>k
    => dp[j]-dp[k]+a*sum[j]^2-a*sum[k]^2+b*sum[k]-b*sum[j]>=sum[i]*2*a*(sum[j]-sum[k])
    => (dp[j]-dp[k]+a*sum[j]^2-a*sum[k]^2+b*sum[k]-b*sum[j])/(2*a*(sum[j]-sum[k]))>=sum[i]

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<queue>
     5 #include<cmath>
     6 #include<vector>
     7 #include<cstdlib>
     8 #include<iostream>
     9 #define ll long long
    10 #define inf 2147483647
    11 #define N 1000005
    12 using namespace std;
    13 ll dp[N],sum[N];
    14 int a,b,c,q[N];
    15 ll pw(ll x){return x*x;}ll S(int j,int k){return 2*a*(sum[j]-sum[k]);}
    16 ll G(int j,int k){return dp[j]-dp[k]+a*pw(sum[j])-a*pw(sum[k])+b*sum[k]-b*sum[j];}
    17 double slope(int j,int k){return (double)G(j,k)/S(j,k);}
    18 
    19 int main(){
    20     int n;
    21     scanf("%d",&n);
    22     scanf("%d%d%d",&a,&b,&c);
    23     for(int i=1;i<=n;i++){
    24         int x;
    25         scanf("%d",&x);
    26         sum[i]=sum[i-1]+x;
    27     }
    28     int h=1,t=2;
    29     for(int i=1;i<=n;i++){
    30         while(h+1<t&&slope(q[h],q[h+1])<=sum[i])h++;
    31         int j=q[h],x=sum[i]-sum[j];
    32         dp[i]=dp[j]+a*pw(x)+b*x+c;
    33         while(h+1<t&&slope(i,q[t-1])<=slope(q[t-1],q[t-2]))t--;
    34         q[t++]=i;
    35     }
    36     printf("%lld",dp[n]);
    37     return 0;
    38 }
  • 相关阅读:
    动网16位gb2312md5加密
    开发windows7侧边栏小工具
    MVC文档地址
    关闭FCNs(文件修改监控)
    内存管理
    android笔记一(Button)
    android笔记五ImageButton
    android笔记三FrameLayout
    linux内核各组件的功能介绍
    C++面试题
  • 原文地址:https://www.cnblogs.com/wsy01/p/8124910.html
Copyright © 2020-2023  润新知