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)的

 

View Code
 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

 

你可能感兴趣的:(ZOJ)