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 }

 

posted @ 2017-12-27 11:30  _wsy  阅读(161)  评论(0编辑  收藏  举报