BZOJ 1010 斜率优化DP
题意:
http://www.lydsy.com/JudgeOnline/problem.php?id=1010
思路:
DP方程不难想:
DP[I]=MIN(DP[J]+(SUM[I]-SUM[J]+I-J-1-L)^2) ,J<I
其中DP[I]表示处理到第I个玩具时最少的费用。
直接来显然TLE,一维方程一般用斜率优化。
先化简下方程:
令F[I]=SUM[I]+I,C=1+L,则化为
DP[I]=MIN(DP[J]+(F[I]-F[J]-C)^2)
以下是用这方法的步骤:
1.证明较优决策点对后续状态影响的持续性
假设在状态I处,有两个决策点J,K(J<K),且决策K比决策J好,即
DP[K]+(F[I]-F[K]-C)^2<=DP[J]+(F[I]-F[J]-C)^2
则,对于状态I之后的某状态T, F[T]=F[I]+V
要证
DP[K]+(F[T]-F[K]-C)^2<=DP[J]+(F[T]-F[J]-C)^2
只需证
DP[K]+(F[I]+V-F[K]-C)^2<=DP[J]+(F[I]+V-F[J]-C)^2
只需证
DP[K]+(F[I]-F[K]-C)^2+2*(F[I]-F[K]-C)*V+V^2<=DP[J]+(F[I]-F[J]-C)^2+2*(F[I]-F[J]-C)*V+V^2
联系假设只需要证:
2*(F[I]-F[K]-C)*V<=2*(F[I]-F[J]-C)*V
即证:
F[K]>=F[J]
F[I]显然为增函数,且J<K,所以上式得证.
2.求斜率方程:一般化为左边是J,K,右边是I的形式
由DP[K]+(F[I]-F[K]-C)^2<=DP[J]+(F[I]-F[J]-C)^2
展开得:
DP[K]+F[I]^2-2*F[I]*(F[K]+C)+(F[K]+C)^2<=DP[J]+F[I]^2-2*F[I]*(F[J]+C)+(F[J]+C)^2
即:
DP[K]+(F[K]+C)^2-DP[J]-(F[J]+C)^2<=2*F[I]*(F[K]-F[J])
即
(DP[K]+(F[K]+C)^2-DP[J]-(F[J]+C)^2)/(2*(F[K]-F[J]))<=F[I]
令
G(K,J)=DP[K]+(F[K]+C)^2-DP[J]-(F[J]+C)^2
S(K,J)=2*(F[K]-F[J])
X(K,J)=G(K,J)/S(K,J)
所以斜率方程为X(K,J)<=F[I]
3.规定队列的维护规则
队首维护:
假设A,B(A<B)是队首元素,若X(B,A)<=F[I],则B比A好,删除A,否则不需维护.
队尾维护:
假设A,B,C(A<B<C)是队尾元素
a.若X(B,A)<=F[I],且X(C,B)<=F[I],则C比B好,B比A好
b.若X(B,A)<=F[I],且X(C,B)>F[I],则B比C好,B比A好,B为极大值
c.若X(B,A)>F[I],A比B好
a,c情况直接删掉B,b情况保留.b情况可改为X(B,A)<X(C,B)
以上内容转自:http://blog.sina.com.cn/s/blog_5f5353cc0100jx41.html
自我总结:
斜率优化的题前提还是很多的。。
正如风炎大神说的:
1.证明较优决策点对后续状态影响的持续性
2.求斜率方程:一般化为左边是J,K,右边是I的形式
3.规定队列的维护规则(这个规则实质上是在维护一个凸性函数,此题为下凸函数,所有转移的点都是凸性函数上的点,而这个凸性函数上的点又符合“较优决策点对后续状态影响的持续性”)
4.此题满足决策单调,转移时0(1)的,对于一些决策不单调的,可以用数据结构做到0(logn)的
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <algorithm> 6 7 #define N 55000 8 9 using namespace std; 10 11 int n; 12 long long c,sum[N],f[N],dp[N]; 13 int q[N]; 14 15 inline void read() 16 { 17 scanf("%d%lld",&n,&c); c+=1; 18 for(int i=1;i<=n;i++) 19 { 20 scanf("%lld",&sum[i]); 21 sum[i]+=sum[i-1]; 22 f[i]=sum[i]+(long long)i; 23 } 24 } 25 26 inline long long S(int x,int y) 27 { 28 return 2*(f[x]-f[y]); 29 } 30 31 inline long long G(int x,int y) 32 { 33 return dp[x]-dp[y]+(f[x]+c)*(f[x]+c)-(f[y]+c)*(f[y]+c); 34 } 35 36 inline void go() 37 { 38 int h=1,t=2; 39 q[1]=0; 40 for(int i=1;i<=n;i++) 41 { 42 while(h<t-1&&G(q[h+1],q[h])<=S(q[h+1],q[h])*f[i]) h++; 43 dp[i]=dp[q[h]]+(f[i]-f[q[h]]-c)*(f[i]-f[q[h]]-c); 44 while(h<t-1&&G(i,q[t-1])*S(q[t-1],q[t-2])<=G(q[t-1],q[t-2])*S(i,q[t-1])) t--; 45 q[t++]=i; 46 } 47 printf("%lld\n",dp[n]); 48 } 49 50 int main() 51 { 52 read(); 53 go(); 54 return 0; 55 }
PS:BZOJ 好似不能用__int64,一用就CE