dp[i] = dp[j] + (a[i] - a[j])^2 + m;
展开得 dp[i] = min{dp[j] + a[i]^2 + a[j]^2 - 2*a[i]*a[j] + m}
其中a[i]^2 是与i相关的变量, 而m是常量,所以可以从表达式中抽离出来
所以只要求 dp[i] = min{dp[j] + a[j]^2 + 2*a[i]*a[j]} 即可,
设k = a[i] , x = 2*a[j], y = dp[j] + a[j]^2,G = dp[i]
那么就是G = -kx + y,
为了得到dp[i]的最小值, 那么需要枚举j,那么相当于二维的坐标系上有很多个点,
然后有一条斜率为-k的直线从y轴下方无限远处慢慢向上平移, 直到经过坐标系上的一个点,
那么此时与y轴的截距G是最小的,
我们只要维护一个凸包就行了。
设红线的斜率为k,直线ab的斜率为kab,
如果k<kab, 那么点a就是最优的,因为如果要经过点a之后的点,就必须把红线往上平移
如果k>kab, 那么点a不是最优的,因为如果要经过点b,是把红线往下移,也就是说点a是可以舍弃的,因为k=a[i],
而a[i]是递增不减的,所以说点a是当前可舍弃,以后也可舍弃的
至于k==kab, 那么点a也是可舍弃的
为什么不在凸包上的点就不可能成为最优点呢?
因为t不在凸包上,所以ktb < kat
如果t可以成为最优的,那么就是说存在一条斜率为k的直线
使得k>=kat且 k<ktb, 然而ktb < kat, 所以这是不可能发生的事情,所以舍弃掉
所以我们就是维护一个凸包就行啦。
1 #include <stdio.h> 2 #include <string.h> 3 #include <math.h> 4 #include <iostream> 5 #include <algorithm> 6 #include <vector> 7 #include <queue> 8 #include <stack> 9 #include <functional> 10 #include <map> 11 #include <set> 12 using namespace std; 13 typedef long long LL; 14 const int INF = 1<<30; 15 /* 16 * */ 17 const int N = 500000 + 10; 18 int a[N]; 19 int dp[N]; 20 int q[N],head,tail; 21 int n,m; 22 int getUp(int k1, int k2) 23 { 24 return (dp[k1]+a[k1]*a[k1]) - (dp[k2]+a[k2]*a[k2]); 25 } 26 int getDown(int k1, int k2) 27 { 28 return a[k1] - a[k2]; 29 } 30 int getDp(int i, int k) 31 { 32 return dp[k] + (a[i] - a[k]) * (a[i] - a[k]) + m; 33 } 34 int main() 35 { 36 //freopen("/Users/whoami/in.txt","r",stdin); 37 while(scanf("%d%d",&n,&m)!=EOF) 38 { 39 memset(dp,0,sizeof(dp)); 40 for(int i=1;i<=n;++i) 41 { 42 scanf("%d",&a[i]); 43 a[i] += a[i-1]; 44 } 45 head = tail = 0; 46 q[tail++] = 0; 47 for(int i=1;i<=n;++i) 48 { 49 /* 50 while(head+1<tail && getDp(i,q[head])<=getDp(i,q[head+1])) 51 head++; 52 */ 53 //得到最优值 54 while(head+1<tail && getUp(q[head+1], q[head])<=2 * a[i] * getDown(q[head+1], q[head])) 55 head++; 56 dp[i] = getDp(i,q[head]); 57 //维护下凸包, 58 while(head+1<tail && getUp(q[tail-1],q[tail-2])*getDown(i,q[tail-1]) >= getUp(i,q[tail-1])*getDown(q[tail-1],q[tail-2])) 59 tail--; 60 q[tail++] = i; 61 62 } 63 printf("%d ",dp[n]); 64 } 65 return 0; 66 }