One day Zero want to print an article which has N words, and each word i has a cost Ci to be printed. Also, Zero know that print k words in one line will cost
M is a const number.
Now Zero want to know the minimum cost in order to arrange the article perfectly.
第一道斜率dp,祭
设dp[i]表示输出前i个的最小费用,那么有如下的DP方程:
dp[i]= min{ dp[j]+(sum[i]-sum[j])^2 +M } 0<j<i
其中 sum[i]表示数字的前i项和。
相信都能理解上面的方程。
直接求解上面的方程的话复杂度是O(n^2)
对于500000的规模显然是超时的。下面讲解下如何用斜率优化DP使得复杂度降低一维。
我们首先假设在算 dp[i]时,k<j ,j点比k点优。
也就是
dp[j]+(sum[i]-sum[j])^2+M <= dp[k]+(sum[i]-sum[k])^2+M;
所谓j比k优就是DP方程里面的值更小
对上述方程进行整理很容易得到:
[(dp[j]+sum[j]*sum[j])-(dp[k]+sum[k]*sum[k])] / 2(sum[j]-sum[k]) <=sum[i].
注意整理中要考虑下正负,涉及到不等号的方向。
左边我们发现如果令:yj=dp[j]+sum[j]*sum[j] xj=2*sum[j]
那么就变成了斜率表达式:(yj-yk)/(xj-xk) <= sum[i];
而且不等式右边是递增的。
所以我们可以看出以下两点:我们令g[k,j]=(yj-yk)/(xj-xk)
第一:如果上面的不等式成立,那就说j比k优,而且随着i的增大上述不等式一定是成立的,也就是对i以后算DP值时,j都比k优。那么k就是可以淘汰的。
第二:如果 k<j<i 而且 g[k,j]>g[j,i] 那么 j 是可以淘汰的。
假设 g[j,i]<sum[i]就是i比j优,那么j没有存在的价值
相反如果 g[j,i]>sum[i] 那么同样有 g[k,j]>sum[i] 那么 k比 j优 那么 j 是可以淘汰的
所以这样相当于在维护一个下凸的图形,斜率在逐渐增大。
通过一个队列来维护。
1 #include "bits/stdc++.h" 2 3 using namespace std; 4 typedef long long ll; 5 6 ll s[600000],f[600000],q[600000]; 7 8 9 ll slope(ll j, ll k) 10 { 11 return ((f[j]+s[j]*s[j])-(f[k]+s[k]*s[k])); 12 13 } 14 ll down(ll j,ll k) 15 { 16 return (2*s[j]-2*s[k]); 17 } 18 19 ll n,m; 20 21 int main() 22 { 23 while (cin>>n>>m) 24 { 25 for (int i=1;i<=n;i++) 26 { 27 ll x;cin>>x;s[i]=s[i-1]+x; 28 } 29 int L=1,R=1; 30 q[1]=f[0]=0; 31 for (int i=1;i<=n;i++) 32 { 33 while (L<R&&slope(q[L+1],q[L])<=s[i]*down(q[L+1],q[L]))L++; 34 //while (L<R&&slope(q[L],q[L+1])>=s[i]*down(q[L],q[L+1]))L++; 35 int t=q[L]; 36 f[i]=f[t]+(ll)pow(s[i]-s[t],2)+m; 37 while(L<R&&slope(q[R],q[R-1])*down(i,q[R])>=down(q[R],q[R-1])*slope(i,q[R]))R--; 38 //while(L<R&&slope(q[R-1],q[R])*down(q[R],i)>=down(q[R-1],q[R])*slope(q[R],i))R--; 39 40 q[++R]=i; 41 } 42 cout<<f[n]<<endl; 43 } 44 45 }