斜率优化DP和四边形不等式优化DP整理

当dp的状态转移方程dp[i]的状态i需要从前面(0~i-1)个状态找出最优子决策做转移时 我们常常需要双重循环

(一重循环跑状态 i,一重循环跑 i 的所有子状态)这样的时间复杂度是O(N^2)而 斜率优化或者四边形不等式优化后的DP

可以将时间复杂度缩减到O(N)

O(N^2)可以优化到O(N) ,O(N^3)可以优化到O(N^2),依次类推

斜率优化DP和四边形不等式优化DP主要的原理就是利用斜率或者四边形不等式等数学方法

在所有要判断的子状态中迅速做出判断,所以这里的优化其实是省去了枚举i的子状态的循环,几乎就是直接把最优的子状态找出来了

其中四边形不等式优化是用数组s边跑边求最优的子状态,例如用s[i][j]保存dp[i][j]的最优子状态

斜率优化的话是将后面可能用到的子状态放到队列中,要求的当前状态的最优状态就是队首元素q[head]

另外,网上见到很多用二分+DP解斜率优化的问题。

以dp求最小值为例:

主要的解题步骤就是先写出dp的状态转移方程,然后选取两个子状态p,q

扫描二维码关注公众号,回复: 2218307 查看本文章

假设p < q而决策q比p更好,求出斜率不等式,然后就可以写了

至于经常有题目控制子决策的范围什么的(比如控制区间长度,或者控制分组的组数),就需要具体情况具体分析

1  HDU 1300 Pearls

最最最简单的斜率DP优化的题,就算不用优化,O(N^2)的算法也可以AC

这题绝壁是最最最适合入门的斜率DP的题,我发誓!!!

版本一:(O(N^2))

  1. #define mem(a,x) memset(a,x,sizeof(a))  
  2. #include<iostream>  
  3. #include<cstdio>  
  4. #include<cstring>  
  5. #include<algorithm>  
  6. #include<queue>  
  7. #include<set>  
  8. #include<stack>  
  9. #include<cmath>  
  10. #include<map>  
  11. #include<stdlib.h>  
  12. #include<cctype>  
  13. #include<string>  
  14. #define Sint(n) scanf("%d",&n)  
  15. #define Sll(n) scanf("%I64d",&n)  
  16. #define Schar(n) scanf("%c",&n)  
  17. #define Schars(s) scanf("%s",s)   
  18. #define Sint2(x,y) scanf("%d %d",&x,&y)  
  19. #define Sll2(x,y) scanf("%I64d %I64d",&x,&y)  
  20. #define Pint(x) printf("%d",x)  
  21. #define Pllc(x,c) printf("%I64d%c",x,c)  
  22. #define Pintc(x,c) printf("%d%c",x,c)  
  23. using namespace std;  
  24. typedef long long ll;  
  25. /* 
  26.     dp[i]表示买前i种珍珠的最少花费 
  27.      
  28.     dp[i] = min(dp[j] + (sum[i] - sum[j] + 10)*w[i]) 
  29.     其中sum[i]-sum[j]表示第j+1种珍珠到第i种珍珠所需的数量 
  30.     w[i]表示第i种珍珠的价值 
  31.       
  32. */  
  33. const int N = 111;  
  34. int w[N],dp[N],sum[N];  
  35. int main()  
  36. {  
  37.     int T;Sint(T);  
  38.     while (T--)  
  39.     {  
  40.         int n;Sint(n);  
  41.         for (int i = 1,x;i <= n;++i)  
  42.         {  
  43.             Sint2(x,w[i]);  
  44.             sum[i] = sum[i-1] + x;  
  45.         }  
  46.         dp[1] = (sum[1]+10)*(w[1]);  
  47.         for (int i = 2;i <= n;++i)  
  48.         {  
  49.             dp[i] = dp[i-1] + (sum[i]-sum[i-1]+10)*w[i];  
  50.             for (int j = 0;j < i-1;++j)  
  51.             {  
  52.                 dp[i] = min(dp[i],dp[j] + (sum[i]-sum[j]+10)*w[i]);  
  53.             }  
  54.         }  
  55.         Pintc(dp[n],'\n');  
  56.     }  
  57.     return 0;  
  58. }  
当做出暴力DP版本之后,只需再多考虑一步就可以变成斜率优化DP

对于状态转移方程dp[i] = dp[j] + (sum[i]-sum[j]+10)*w[i]

考虑 k < j < i 且假设 i状态由j状态转移得到比由k状态转移得到更优

即:dp[j] + (sum[i]-sum[j]+10)*w[i] <= dp[k] + (sum[i] - sum[k] + 10)*w[i]

(这里取小于号是因为dp保存的是最小花费,花费越小越好,取等是因为j比k大,所以就算k,j一样优也选j)

这个不等式化简之后就是

dp[j] - dp[k] <= w[i]*(sum[j]-sum[k])

这里的w[i]满足单调递增

有了上面的不等式和单调条件就可以斜率优化了,主要做法就是利用单调队列维护满足的点

比如j状态优于k状态,就可以将k永远的剔除了

具体对于子状态的维护见代码里面有2个对队列进行的删除的操作,一个是在求dp[i]时在队首删除

一个是在将状态i加入队列时在队尾删除的操作

版本二:(O(N))

  1. #define mem(a,x) memset(a,x,sizeof(a))  
  2. #include<iostream>  
  3. #include<cstdio>  
  4. #include<cstring>  
  5. #include<algorithm>  
  6. #include<queue>  
  7. #include<set>  
  8. #include<stack>  
  9. #include<cmath>  
  10. #include<map>  
  11. #include<stdlib.h>  
  12. #include<cctype>  
  13. #include<string>  
  14. #define Sint(n) scanf("%d",&n)  
  15. #define Sll(n) scanf("%I64d",&n)  
  16. #define Schar(n) scanf("%c",&n)  
  17. #define Schars(s) scanf("%s",s)   
  18. #define Sint2(x,y) scanf("%d %d",&x,&y)  
  19. #define Sll2(x,y) scanf("%I64d %I64d",&x,&y)  
  20. #define Pint(x) printf("%d",x)  
  21. #define Pllc(x,c) printf("%I64d%c",x,c)  
  22. #define Pintc(x,c) printf("%d%c",x,c)  
  23. using namespace std;  
  24. typedef long long ll;  
  25. /* 
  26.     dp[i]表示买前i种珍珠的最少花费 
  27.      
  28.     dp[i] = min(dp[j] + (sum[i] - sum[j] + 10)*w[i]) 
  29.     其中sum[i]-sum[j]表示第j+1种珍珠到第i种珍珠所需的数量 
  30.     w[i]表示第i种珍珠的价值 
  31.      
  32.     dp[j] - dp[k] <= w[i]*(sum[j]-sum[k]) 
  33.     The qualities of the classes (and so the prices) are given in ascending order. 
  34.     So w[i]单增 --斜率DP  
  35. */  
  36. const int N = 111;  
  37. int w[N],dp[N],sum[N];  
  38. int q[N];  
  39. int DP(int i,int j)  
  40. {  
  41.     return dp[j] + (sum[i]-sum[j]+10)*w[i];  
  42. }  
  43. int dy(int i,int j)  
  44. {  
  45.     return dp[i]-dp[j];  
  46. }  
  47. int dx(int i,int j)  
  48. {  
  49.     return sum[i]-sum[j];  
  50. }  
  51. int main()  
  52. {  
  53.     int T;Sint(T);  
  54.     while (T--)  
  55.     {  
  56.         int n;Sint(n);  
  57.         for (int i = 1,x;i <= n;++i)  
  58.         {  
  59.             Sint2(x,w[i]);  
  60.             sum[i] = sum[i-1] + x;  
  61.     }  
  62.         int head = 0,tail = 0;  
  63.         q[tail++] = 0;  
  64.         for (int i = 1;i <= n;++i)  
  65.         {  
  66.             while (head+1<tail&&dy(q[head+1],q[head])<=w[i]*dx(q[head+1],q[head])) ++head;  
  67.             dp[i] = DP(i,q[head]);  
  68.             while (head+1<tail&&dy(i,q[tail-1])*dx(q[tail-1],q[tail-2])<=dy(q[tail-1],q[tail-2])*dx(i,q[tail-1])) --tail;  
  69.             q[tail++] = i;  
  70.         }  
  71.         Pintc(dp[n],'\n');  
  72.     }  
  73.     return 0;  
  74. }  

POJ 1260 Pearls   和上面一题一样的


3.HDU 3507 Print Article 


列状态转移方程 然后假设 k < j < i 且j决策更好 不等式列出来就好了
  1. #define mem(a,x) memset(a,x,sizeof(a))  
  2. #include<iostream>  
  3. #include<cstdio>  
  4. #include<cstring>  
  5. #include<algorithm>  
  6. #include<queue>  
  7. #include<set>  
  8. #include<stack>  
  9. #include<cmath>  
  10. #include<map>  
  11. #include<stdlib.h>  
  12. #define Sint(n) scanf("%d",&n)  
  13. #define Sll(n) scanf("%I64d",&n)  
  14. #define Schar(n) scanf("%c",&n)  
  15. #define Sint2(x,y) scanf("%d %d",&x,&y)  
  16. #define Sll2(x,y) scanf("%I64d %I64d",&x,&y)  
  17. #define Pint(x) printf("%d",x)  
  18. #define Pllc(x,c) printf("%I64d%c",x,c)  
  19. #define Pintc(x,c) printf("%d%c",x,c)  
  20. using namespace std;  
  21. typedef long long ll;  
  22. const int N = 500007;  
  23. int dp[N];  
  24. int sum[N];  
  25. int q[N];  
  26. int n,m;  
  27. int EX(int x)  
  28. {  
  29.     return x*x;  
  30. }  
  31. int getDP(int i,int j)  
  32. {  
  33.     return dp[j] + m + EX(sum[i]-sum[j]);  
  34. }  
  35. int getUP(int j,int k)//yj - yk   
  36. {  
  37.     return (dp[j] + EX(sum[j])) - (dp[k] + EX(sum[k]));  
  38. }  
  39. int getDown(int j,int k)//xj - xk  
  40. {  
  41.     return 2*(sum[j] - sum[k]);  
  42. }  
  43. int main()  
  44. {  
  45.       
  46.     while (Sint2(n,m) == 2)  
  47.     {  
  48.         for (int i = 1,x;i <= n;++i)  
  49.         {  
  50.             Sint(x);  
  51.             sum[i] = sum[i-1] + x;  
  52.         }  
  53.         int head = 0,tail = 0;  
  54.         q[tail++] = 0;//单调队列 (单增)   
  55.         for (int i = 1;i <= n;++i)  
  56.         {  
  57.             //                  getup/getdown  <= sum[i]  
  58.             while (head+1<tail&&getUP(q[head+1],q[head])<=sum[i]*getDown(q[head+1],q[head])) head++;  
  59.             dp[i] = getDP(i,q[head]);  
  60.             //          getup(i,q[tail-1])/getdown(i,q[tail-1]) <= getup(q[tail-1],q[tail-2])/getdown(q[tail-1],q[tail-2])  
  61.             while (head+1<tail&&getUP(i,q[tail-1])*getDown(q[tail-1],q[tail-2])<=getUP(q[tail-1],q[tail-2])*getDown(i,q[tail-1]))tail--;  
  62.             q[tail++] = i;  
  63.         }  
  64.         Pintc(dp[n],'\n');  
  65.     }  
  66.     return 0;  
  67. }  


4.HDU 2829 Lawrence

  1. #define mem(a,x) memset(a,x,sizeof(a))  
  2. #include<iostream>  
  3. #include<cstdio>  
  4. #include<cstring>  
  5. #include<algorithm>  
  6. #include<queue>  
  7. #include<set>  
  8. #include<stack>  
  9. #include<cmath>  
  10. #include<map>  
  11. #include<stdlib.h>  
  12. #include<cctype>  
  13. #include<string>  
  14. #define Sint(n) scanf("%d",&n)  
  15. #define Sll(n) scanf("%I64d",&n)  
  16. #define Schar(n) scanf("%c",&n)  
  17. #define Sint2(x,y) scanf("%d %d",&x,&y)  
  18. #define Schars(s) scanf("%s",s)   
  19. #define Sll2(x,y) scanf("%I64d %I64d",&x,&y)  
  20. #define Pint(x) printf("%d",x)  
  21. #define Pllc(x,c) printf("%I64d%c",x,c)  
  22. #define Pintc(x,c) printf("%d%c",x,c)  
  23. using namespace std;  
  24. typedef long long ll;  
  25. /* 
  26.     dp[i][j]表示前j个数分成i组的最小价值 
  27.     sum[i]表示前i个数的和 
  28.     cost[i]表示前i个数的花费  
  29. */  
  30. const int N = 1004;  
  31. int sum[N],cost[N],dp[N][N];  
  32. int q[N],head,tail;  
  33. int n,m;  
  34. int EX(int x)  
  35. {  
  36.     return x*x;  
  37. }  
  38. int dy(int x,int j,int i)  
  39. {  
  40.     return dp[x][i] - cost[i] + EX(sum[i]) - (dp[x][j] - cost[j] + EX(sum[j]));  
  41. }  
  42. int dx(int j,int i)  
  43. {  
  44.     return sum[i] - sum[j];  
  45. }  
  46. int DP(int x,int j,int i)  
  47. {  
  48.     return dp[x][i]+cost[j] - cost[i] - sum[i]*(sum[j]-sum[i]);  
  49. }  
  50. int main()  
  51. {  
  52.     while (Sint2(n,m)==2&&(n||m))  
  53.     {  
  54.         ++m;  
  55.         for (int i = 1,x;i <= n;++i)  
  56.         {  
  57.             Sint(x);  
  58.             sum[i] = sum[i-1] + x;  
  59.             cost[i] = cost[i-1] + sum[i-1]*x;  
  60.         }  
  61.         for (int i = 1;i <= n;++i) dp[1][i] = cost[i];  
  62.         for(int i = 2;i <= m;++i)  
  63.         {  
  64.             head = tail = 0;  
  65.             q[tail++] = i-1;  
  66.             for (int j = i;j <= n;++j)  
  67.             {  
  68.                 while (head+1<tail&&dy(i-1,q[head],q[head+1])<=sum[j]*dx(q[head],q[head+1])) head++;  
  69.                 dp[i][j] = DP(i-1,j,q[head]);  
  70.                 while (head+1<tail&&dx(q[tail-2],q[tail-1])*dy(i-1,q[tail-1],j)<=dy(i-1,q[tail-2],q[tail-1])*dx(q[tail-1],j)) --tail;  
  71.                 q[tail++] = j;  
  72.             }  
  73.         }  
  74.         Pintc(dp[m][n],'\n');  
  75.     }  
  76.     return 0;  
  77. }  


5.HDU 2993 MAX Average Problem

这题、、、

如果现在有人能过的话请联系博主 ,不胜感基、、、

6.UVALive 5097 - Cross the Wall

贪心处理下

  1. #define mem(a,x) memset(a,x,sizeof(a))  
  2. #include<iostream>  
  3. #include<cstdio>  
  4. #include<cstring>  
  5. #include<algorithm>  
  6. #include<queue>  
  7. #include<set>  
  8. #include<stack>  
  9. #include<cmath>  
  10. #include<map>  
  11. #include<stdlib.h>  
  12. #include<cctype>  
  13. #include<string>  
  14. #define Sint(n) scanf("%d",&n)  
  15. #define Sll(n) scanf("%lld",&n)  
  16. #define Schar(n) scanf("%c",&n)  
  17. #define Schars(s) scanf("%s",s)   
  18. #define Sint2(x,y) scanf("%d %d",&x,&y)  
  19. #define Sll2(x,y) scanf("%lld %lld",&x,&y)  
  20. #define Pint(x) printf("%d",x)  
  21. #define Pllc(x,c) printf("%lld%c",x,c)  
  22. #define Pintc(x,c) printf("%d%c",x,c)  
  23. using namespace std;  
  24. typedef long long ll;  
  25. /* 
  26.     dp[i][j]表示 前i个人挖j个洞的最小花费 
  27.     1.当w[i] <= w[j] && h[i]<=h[j]时 舍弃 (w[i],h[i]) 
  28.     2.将人按w递增 h递减 排序,即满足 w[j] < w[i]&&h[j] > h[i] 
  29.      
  30.     故dp[i][j] = dp[k][j-1] + w[i]*h[k+1] 
  31.       
  32. */  
  33. const int N = 500007;  
  34.   
  35. struct Node  
  36. {  
  37.     ll h,w;  
  38. }b[N];  
  39. int q[N],head,tail;  
  40. bool cmp(Node a,Node b)  
  41. {  
  42.     if (a.h == b.h) return a.w > b.w;  
  43.     return a.h > b.h;//确保h递减   
  44. }  
  45. ll dp[N][104];  
  46. ll dy(int j,int k,int t)  
  47. {  
  48.     return dp[j][t] - dp[k][t];  
  49. }  
  50. ll dx(int j,int k)  
  51. {  
  52.     return b[k+1].h - b[j+1].h;  
  53. }  
  54. int main()  
  55. {  
  56.     int n,k;  
  57.     while (Sint2(n,k) == 2)  
  58.     {  
  59.         for (int i = 1;i <= n;++i)  
  60.         {  
  61.             Sll2(b[i].w,b[i].h);  
  62.         }  
  63.         sort(b+1,b+n+1,cmp);  
  64.         int t = 1;  
  65.         for (int i = 1;i <= n;++i)  
  66.         {  
  67.             if (b[t].w < b[i].w) b[++t] = b[i];  
  68.         }  
  69. //      cout<<t<<endl;   
  70.         k = min(t,k);  
  71.         for (int i = 1;i <= t;++i) dp[i][1] = b[i].w*b[1].h;  
  72.         for (int j = 2;j <= k;++j)  
  73.         {  
  74.             head = tail = 0;mem(q,0);  
  75.             q[tail++] = 0;  
  76.             for (int i = 1;i <= t;++i)  
  77.             {  
  78.                 while (head+1<tail&&dy(q[head+1],q[head],j-1) <= b[i].w * dx(q[head+1],q[head])) ++head;  
  79.                 dp[i][j] = dp[q[head]][j-1] + b[i].w * b[q[head]+1].h;  
  80.                 while (head+1<tail&&dy(i,q[tail-1],j-1)*dx(q[tail-1],q[tail-2]) <= dy(q[tail-1],q[tail-2],j-1)*dx(i,q[tail-1])) --tail;  
  81.                 q[tail++] = i;  
  82.             }  
  83.         }  
  84.         ll ans = dp[t][1];  
  85.         for (int i = 2;i <= k;++i)  
  86.         {  
  87.             ans = min(ans,dp[t][i]);  
  88.         }  
  89.         Pllc(ans,'\n');  
  90.     }  
  91.     return 0;  
  92. }  


7.HDU 3045 Picnic Cows

  1. #define mem(a,x) memset(a,x,sizeof(a))  
  2. #include<iostream>  
  3. #include<cstdio>  
  4. #include<cstring>  
  5. #include<algorithm>  
  6. #include<queue>  
  7. #include<set>  
  8. #include<stack>  
  9. #include<cmath>  
  10. #include<map>  
  11. #include<stdlib.h>  
  12. #include<cctype>  
  13. #include<string>  
  14. #define Sint(n) scanf("%d",&n)  
  15. #define Sll(n) scanf("%I64d",&n)  
  16. #define Schar(n) scanf("%c",&n)  
  17. #define Schars(s) scanf("%s",s)   
  18. #define Sint2(x,y) scanf("%d %d",&x,&y)  
  19. #define Sll2(x,y) scanf("%I64d %I64d",&x,&y)  
  20. #define Pint(x) printf("%d",x)  
  21. #define Pllc(x,c) printf("%I64d%c",x,c)  
  22. #define Pintc(x,c) printf("%d%c",x,c)  
  23. using namespace std;  
  24. typedef long long ll;  
  25. /* 
  26. Cows in the same team should reduce their Moo~ to the one who has the lowest Moo~ in this team 
  27.  
  28.     dp[i]表示前i头牛的最小花费 
  29.     dp[i] = dp[j] + (sum[i]-sum[j]-(i-j)*a[j+1])  
  30.     dp[j]-dp[k]+sum[k]-sum[j]+j*a[j+1]-k*a[k+1] < i*(a[j+1]-a[k+1]) 
  31. */  
  32. const int N = 400004;  
  33. ll dp[N],a[N],sum[N];  
  34. int q[N],head,tail;  
  35. ll dy(int j,int k)  
  36. {  
  37.     return dp[j]-dp[k] + sum[k]-sum[j] + j*a[j+1]-k*a[k+1];  
  38. }  
  39. ll dx(int j,int k)  
  40. {  
  41.     return a[j+1] - a[k+1];  
  42. }  
  43. ll DP(int i,int j)  
  44. {  
  45.     return dp[j] + (sum[i]-sum[j]-(i-j)*a[j+1]);  
  46. }  
  47. int main()  
  48. {  
  49.     int n,t;  
  50.     while (Sint2(n,t) == 2)  
  51.     {  
  52.         for (int i = 1;i <= n;++i) Sll(a[i]);  
  53.         sort(a+1,a+n+1);  
  54.         for (int i = 1;i <= n;++i) sum[i] = sum[i-1] + a[i];  
  55.         head = tail = 0;  
  56.         q[tail++] = 0;  
  57.         for (int i = 1;i <= n;++i)  
  58.         {  
  59.             while (head+1<tail&&dy(q[head+1],q[head]) <= i*dx(q[head+1],q[head])) ++head;  
  60.             dp[i] = DP(i,q[head]);  
  61.             int j = i-t+1;  
  62.             if (j < t) continue;  
  63.             while (head+1<tail&&dy(j,q[tail-1])*dx(q[tail-1],q[tail-2])<=dy(q[tail-1],q[tail-2])*dx(j,q[tail-1])) --tail;  
  64.             q[tail++] = j;  
  65.         }  
  66.         Pllc(dp[n],'\n');  
  67.     }  
  68.     return 0;  
  69. }  

8.HDU 3516 Tree Construction

斜率DP写的怎么都过不了,最后用四边形不等式,要保证j-i递增于是枚举长度

  1. #define mem(a,x) memset(a,x,sizeof(a))  
  2. #include<iostream>  
  3. #include<cstdio>  
  4. #include<cstring>  
  5. #include<algorithm>  
  6. #include<queue>  
  7. #include<set>  
  8. #include<stack>  
  9. #include<cmath>  
  10. #include<map>  
  11. #include<stdlib.h>  
  12. #include<cctype>  
  13. #include<string>  
  14. #define Sint(n) scanf("%d",&n)  
  15. #define Sll(n) scanf("%I64d",&n)  
  16. #define Schar(n) scanf("%c",&n)  
  17. #define Schars(s) scanf("%s",s)   
  18. #define Sint2(x,y) scanf("%d %d",&x,&y)  
  19. #define Sll2(x,y) scanf("%I64d %I64d",&x,&y)  
  20. #define Pint(x) printf("%d",x)  
  21. #define Pllc(x,c) printf("%I64d%c",x,c)  
  22. #define Pintc(x,c) printf("%d%c",x,c)  
  23. using namespace std;  
  24. typedef long long ll;  
  25. /* 
  26.     dp[i][j]表示从i到j所需的最小花费 
  27.     dp[i][j] = min {dp[i][k] + dp[k+1][j] + w(i,k,j)} 
  28.     w(i,k,j) = y[k] - y[j] + x[k+1] - x[i] 
  29.     s[i][j] = k 表示 dp[i][j]这个状态最优的决策是 k  
  30. */  
  31. const int N = 1003;  
  32. const int inf = 0x3f3f3f3f;  
  33. int dp[N][N],s[N][N];  
  34. int x[N],y[N];  
  35. int w(int i,int k,int j)  
  36. {  
  37.     if (k >= j) return inf;  
  38.     return y[k] - y[j] + x[k+1] - x[i];  
  39. }  
  40. int DP(const int &n)  
  41. {  
  42.     mem(dp,0);int tmp;  
  43.     for (int L = 2;L<=n;++L) //以j-i递增为顺序递推  
  44.     {  
  45.         for (int i = 1,j = L;i+L-1<=n;++i,j = i+L-1)//i 是 区间左端点,j是区间右端点  
  46.         {  
  47.             dp[i][j] = inf;  
  48.             for (int k = s[i][j-1];k <= s[i+1][j];++k)  
  49.             {  
  50.                 tmp = dp[i][k] + dp[k+1][j] + w(i,k,j);  
  51.                 if (tmp < dp[i][j])  
  52.                 {  
  53.                     dp[i][j] = tmp;  
  54.                     s[i][j] = k;  
  55.                 }  
  56.             }  
  57.         }   
  58.     }   
  59.     return dp[1][n];  
  60. }  
  61. int main()  
  62. {  
  63.     int n;  
  64.     while (Sint(n) == 1)  
  65.     {  
  66.         for (int i = 1;i <= n;++i)   
  67.         {  
  68.             Sint2(x[i],y[i]);  
  69.             s[i][i] = i;  
  70.         }  
  71.         Pintc(DP(n),'\n');  
  72.     }  
  73.     return 0;  
  74. }  


9.POJ 1160 Post Office

状态转移方程写的好的话不用优化也可以过 

这个题的状态转移的方程很经典啊

  1. #define mem(a,x) memset(a,x,sizeof(a))  
  2. #include<iostream>  
  3. #include<cstdio>  
  4. #include<cstring>  
  5. #include<algorithm>  
  6. #include<queue>  
  7. #include<set>  
  8. #include<stack>  
  9. #include<cmath>  
  10. #include<map>  
  11. #include<stdlib.h>  
  12. #include<cctype>  
  13. #include<string>  
  14. #define Sint(n) scanf("%d",&n)  
  15. #define Sll(n) scanf("%I64d",&n)  
  16. #define Schar(n) scanf("%c",&n)  
  17. #define Schars(s) scanf("%s",s)  
  18. #define Sint2(x,y) scanf("%d %d",&x,&y)  
  19. #define Sll2(x,y) scanf("%I64d %I64d",&x,&y)  
  20. #define Pint(x) printf("%d",x)  
  21. #define Pllc(x,c) printf("%I64d%c",x,c)  
  22. #define Pintc(x,c) printf("%d%c",x,c)  
  23. using namespace std;  
  24. typedef long long ll;  
  25. const int inf = 0x3f3f3f3f;  
  26. /* 
  27.     dp[i][j]表示在前i个村庄建j个邮局的最小值 
  28.     d[i][j]表示在[i,j]区间建1个邮局的最小值 
  29.     dp[i][j] = min{dp[k][j-1] + d[k+1][j]} (1<=k<j) 
  30. */  
  31. const int N = 304;  
  32. int V,P;  
  33. int x[N];  
  34. int dp[N][33];  
  35. int d[N][N];  
  36. int DP()  
  37. {  
  38.     for (int i = 1;i <= V;++i)  
  39.     {  
  40.         for (int j = i+1;j <= V;++j)  
  41.         {  
  42.             d[i][j] = d[i][j-1] + x[j] - x[(i+j)/2];  
  43.         }  
  44.     }  
  45.     for (int i = 1;i <= V;++i) dp[i][0] = inf;  
  46.     for (int i = 1;i <= V;++i)  
  47.     {  
  48.         for (int j = 1;j <= min(i,P);++j)  
  49.         {  
  50. //            if (j > P) break;  
  51.             dp[i][j] = inf;  
  52.             for (int k = j-1;k < i;++k)  
  53.             {  
  54.                 dp[i][j] = min(dp[i][j],dp[k][j-1]+d[k+1][i]);  
  55.             }  
  56.         }  
  57.     }  
  58.     return dp[V][P];  
  59. }  
  60. int main()  
  61. {  
  62.     while (Sint2(V,P) == 2)  
  63.     {  
  64.         for (int i = 1;i <= V;++i) Sint(x[i]);  
  65.         sort(x+1,x+V+1);  
  66.         Pintc(DP(),'\n');  
  67.     }  
  68.     return 0;  
  69. }  

10.POJ 1180 Batch Scheduling

  1. #define mem(a,x) memset(a,x,sizeof(a))  
  2. #include<iostream>  
  3. #include<cstdio>  
  4. #include<cstring>  
  5. #include<algorithm>  
  6. #include<queue>  
  7. #include<set>  
  8. #include<stack>  
  9. #include<cmath>  
  10. #include<map>  
  11. #include<stdlib.h>  
  12. #include<cctype>  
  13. #include<string>  
  14. #define Sint(n) scanf("%d",&n)  
  15. #define Sll(n) scanf("%I64d",&n)  
  16. #define Schar(n) scanf("%c",&n)  
  17. #define Schars(s) scanf("%s",s)   
  18. #define Sint2(x,y) scanf("%d %d",&x,&y)  
  19. #define Sll2(x,y) scanf("%I64d %I64d",&x,&y)  
  20. #define Pint(x) printf("%d",x)  
  21. #define Pllc(x,c) printf("%I64d%c",x,c)  
  22. #define Pintc(x,c) printf("%d%c",x,c)  
  23. using namespace std;  
  24. typedef long long ll;  
  25. const int inf = 0x3f3f3f3f;  
  26. /* 
  27.     dp[i]表示前i个job的最小花费 
  28.     dp[i] = dp[j] + (S+sumt[i] - sumt[j]) *(sumf[i]-sumf[j]) 
  29. */   
  30. const int N = 10004;  
  31. ll dp[N];  
  32. ll sumt[N],sumf[N];  
  33. ll t[N],f[N];   
  34. int S,n;  
  35. int q[N],head,tail;  
  36. ll dy(int j,int k)  
  37. {  
  38.     return dp[j] - dp[k];  
  39. }  
  40. ll dx(int j,int k)  
  41. {  
  42.     return sumt[j] - sumt[k];  
  43. }  
  44. ll DP(int i,int j)  
  45. {  
  46.     return dp[j] + (S + sumt[i]-sumt[j])*sumf[i];  
  47. }  
  48. int main()  
  49. {  
  50.     while (Sint2(n,S) == 2)  
  51.     {  
  52.         for (int i = n;i >= 1;--i) Sll2(t[i],f[i]);  
  53.         for (int i = 1;i <= n;++i)  
  54.         {  
  55.             sumt[i] = sumt[i-1] + t[i];  
  56.             sumf[i] = sumf[i-1] + f[i];  
  57.         }  
  58.         head = tail = 0;  
  59.         q[tail++] = 0;  
  60.         for (int i = 1;i <= n;++i)  
  61.         {  
  62.             while (head+1<tail&&dy(q[head],q[head+1])>dx(q[head],q[head+1])*sumf[i]) ++head;  
  63.             dp[i] = DP(i,q[head]);  
  64.             while (head+1<tail&&dy(q[tail-1],i)*dx(q[tail-2],q[tail-1])<dy(q[tail-2],q[tail-1])*dx(q[tail-1],i)) --tail;  
  65.             q[tail++] = i;  
  66.         }  
  67.         Pllc(dp[n],'\n');  
  68.     }  
  69.     return 0;  
  70. }  


11.POJ 2018 Best Cow Fences

二分做的。。。。

  1. #define mem(a,x) memset(a,x,sizeof(a))  
  2. #include<iostream>  
  3. #include<cstdio>  
  4. #include<cstring>  
  5. #include<algorithm>  
  6. #include<queue>  
  7. #include<set>  
  8. #include<stack>  
  9. #include<cmath>  
  10. #include<map>  
  11. #include<stdlib.h>  
  12. #include<cctype>  
  13. #include<string>  
  14. #define Sint(n) scanf("%d",&n)  
  15. #define Sdb(n) scanf("%lf",&n)  
  16. #define Sll(n) scanf("%I64d",&n)  
  17. #define Schar(n) scanf("%c",&n)  
  18. #define Schars(s) scanf("%s",s)   
  19. #define Sint2(x,y) scanf("%d %d",&x,&y)  
  20. #define Sll2(x,y) scanf("%I64d %I64d",&x,&y)  
  21. #define Pint(x) printf("%d",x)  
  22. #define Pllc(x,c) printf("%I64d%c",x,c)  
  23. #define Pintc(x,c) printf("%d%c",x,c)  
  24. using namespace std;  
  25. typedef long long ll;  
  26. const int inf = 0x3f3f3f3f;  
  27. /* 
  28.     虽然据说 斜率DP 更牛逼 
  29.     虽然据说 二分很 low 
  30.     。。。 。。。  
  31. */  
  32. const int N = 100004;  
  33. const double esp = 1e-7;  
  34. double a[N],sum[N];  
  35. int n,f;//n块地至少分f分  
  36. bool ok(double mid)  
  37. {  
  38.     double div = sum[f-1] - (f-1)*mid;  
  39.     for (int i = f;i <= n;++i)  
  40.     {  
  41.         div += a[i] - mid;  
  42.         div = max(div,sum[i]-sum[i-f]-f*mid);  
  43.         if (div > -esp) return 1;  
  44.     }  
  45.     return 0;  
  46. }   
  47. int main()  
  48. {  
  49.     while (Sint2(n,f) == 2)  
  50.     {  
  51.         double l = inf,r = 0;  
  52.         for (int i = 1;i <= n;++i)  
  53.         {  
  54.             Sdb(a[i]);  
  55.             sum[i] = sum[i-1] + a[i];  
  56.             l = min(l,a[i]);  
  57.             r = max(r,a[i]);  
  58.         }  
  59.         while (r-l>=esp)  
  60.         {  
  61.             double mid = (l+r)/2.0;  
  62.             if (ok(mid)) l = mid;  
  63.             else r = mid;  
  64.         }  
  65.         Pintc((int)(r*1000),'\n');  
  66.     }  
  67.     return 0;  
  68. }  


12.POJ 3709 K-Anonymous Sequence

  1. #define mem(a,x) memset(a,x,sizeof(a))  
  2. #include<iostream>  
  3. #include<cstdio>  
  4. #include<cstring>  
  5. #include<algorithm>  
  6. #include<queue>  
  7. #include<set>  
  8. #include<stack>  
  9. #include<cmath>  
  10. #include<map>  
  11. #include<stdlib.h>  
  12. #include<cctype>  
  13. #include<string>  
  14. #define Sint(n) scanf("%d",&n)  
  15. #define Sll(n) scanf("%I64d",&n)  
  16. #define Schar(n) scanf("%c",&n)  
  17. #define Schars(s) scanf("%s",s)   
  18. #define Sint2(x,y) scanf("%d %d",&x,&y)  
  19. #define Sll2(x,y) scanf("%I64d %I64d",&x,&y)  
  20. #define Pint(x) printf("%d",x)  
  21. #define Pllc(x,c) printf("%I64d%c",x,c)  
  22. #define Pintc(x,c) printf("%d%c",x,c)  
  23. using namespace std;  
  24. typedef long long ll;  
  25. const int inf = 0x3f3f3f3f;  
  26. /* 
  27.     dp[i]表示前i个数的最小值 
  28.     dp[i] = dp[j] + (sum[i]-sum[j]) - (i-j)*a[j+1]  
  29.      
  30.     dp[j]-dp[k] - (sum[j]-sum[k]) + j*a[j+1] - k*a[k+1] 
  31.     < i*(a[j+1]-a[k+1])  
  32. */  
  33. const int N = 500004;  
  34. ll dp[N];  
  35. ll sum[N];  
  36. ll a[N];  
  37. int q[N],head,tail;  
  38. int n,k;  
  39. ll dy(int j,int k)  
  40. {  
  41.     return dp[j]-dp[k] - (sum[j]-sum[k]) + j*a[j+1] - k*a[k+1];  
  42. }  
  43. ll  dx(int j,int k)  
  44. {  
  45.     return a[j+1] - a[k+1];  
  46. }  
  47. ll DP(int i,int j)  
  48. {  
  49.       
  50.     return dp[j] + (sum[i]-sum[j]) - (i-j)*a[j+1];  
  51. }  
  52. int main()  
  53. {  
  54.     int T;Sint(T);  
  55.     while (T--)  
  56.     {  
  57.         Sint2(n,k);  
  58.         for (int i = 1;i <= n;++i)  
  59.         {  
  60.             Sll(a[i]);  
  61.             sum[i] = sum[i-1] + a[i];  
  62.         }  
  63.         head = tail = 0;  
  64.         q[tail++] = 0;  
  65.         for (int i = k;i <= n;++i)  
  66.         {  
  67.             while (head+1<tail&&dy(q[head+1],q[head])<=i*dx(q[head+1],q[head])) ++head;  
  68.             dp[i] = DP(i,q[head]);  
  69. //          cout<<"head = "<<q[head]<<" : ";  
  70. //          printf("dp[%d] = %d\n",i,dp[i]);  
  71.             int j = i - k + 1;  
  72.             if (j < k) continue;  
  73.             while (head+1<tail&&dy(j,q[tail-1])*dx(q[tail-1],q[tail-2])<=dy(q[tail-1],q[tail-2])*dx(j,q[tail-1])) --tail;  
  74.             q[tail++] = j;   
  75.         }  
  76.         Pllc(dp[n],'\n');  
  77.     }  
  78.     return 0;  
  79. }  


13.UVA 12594 Naming Babies(找不到链接额。。。)

和第9题一样的想法  但是存不下  换了个方法

  1. #define mem(a,x) memset(a,x,sizeof(a))  
  2. #include<iostream>  
  3. #include<cstdio>  
  4. #include<cstring>  
  5. #include<algorithm>  
  6. #include<queue>  
  7. #include<set>  
  8. #include<stack>  
  9. #include<cmath>  
  10. #include<map>  
  11. #include<stdlib.h>  
  12. #include<cctype>  
  13. #include<string>  
  14. #define Sint(n) scanf("%d",&n)  
  15. #define Sll(n) scanf("%I64d",&n)  
  16. #define Schar(n) scanf("%c",&n)  
  17. #define Schars(s) scanf("%s",s)   
  18. #define Sint2(x,y) scanf("%d %d",&x,&y)  
  19. #define Sll2(x,y) scanf("%I64d %I64d",&x,&y)  
  20. #define Pint(x) printf("%d",x)  
  21. #define Pllc(x,c) printf("%I64d%c",x,c)  
  22. #define Pintc(x,c) printf("%d%c",x,c)  
  23. using namespace std;  
  24. typedef long long ll;  
  25. const int inf = 0x3f3f3f3f;  
  26. /* 
  27.     dp[i][j]表示前i个字符分成j份的最小值 
  28.     d[i][j]表示 [i,j] 当成一份的花费  
  29.     dp[i][j] = dp[k][j-1] + d[k+1][j] 
  30.     but d[20000][20000]开不下。。。 
  31.     so 换个方法算d[i][j] 
  32.     sum1[i]表示前i个数的和 
  33.     sum2[i]表示 求和((i-1)*a[i]) 
  34.     sum3[i]表示 求和(a[i]*a[i]) 
  35.     故  
  36.     dp[i][j] = dp[k][j-1] + sum2[i] - sum2[k] - k*(sum1[i]-sum1[k]) - (sum3[i] - sum3[k]) 
  37.       
  38. */  
  39. const int N = 20004;  
  40. ll dp[N][504],sum1[N],sum2[N],sum3[N];  
  41. int a[N];  
  42. int mp[30];  
  43. char NP[30];  
  44. char NM[N];  
  45. int q[N],head,tail;  
  46. int K;  
  47. int n;  
  48. void init()  
  49. {  
  50.     Schars(NP);Sint(K);  
  51.     Schars(NM);  
  52.     for (int i = 0;i < strlen(NP);++i)  
  53.     {  
  54.         mp[NP[i] - 'a'] = i;   
  55.     }   
  56.     n = strlen(NM);  
  57.     for (int i = 0;i < n;++i)  
  58.     {  
  59.         a[i+1] = mp[NM[i] - 'a'];  
  60.     }  
  61.     for (int i = 1;i <= n;++i)  
  62.     {  
  63.         sum1[i] = sum1[i-1] + a[i];  
  64.         sum2[i] = sum2[i-1] + (i-1)*a[i];  
  65.         sum3[i] = sum3[i-1] + a[i]*a[i];  
  66.     }  
  67. }  
  68. //dp[i][j] = dp[k][j-1] + sum2[i] - sum2[k] - k*(sum1[i]-sum1[k]) - (sum3[i] - sum3[k])  
  69. ll DP(int i,int j,int k)  
  70. {  
  71.     return dp[k][j-1] + sum2[i] - sum2[k] - k*(sum1[i] - sum1[k]) - (sum3[i] - sum3[k]);  
  72. }  
  73. ll dy(int j,int q,int p)  
  74. {  
  75.     return dp[q][j-1]-dp[p][j-1] + q*sum1[q] - p*sum1[p] - (sum2[q]-sum2[p]) + (sum3[q]-sum3[p]);  
  76. }  
  77. ll dx(int q,int p)  
  78. {  
  79.     return q-p;  
  80. }  
  81. ll solve()  
  82. {  
  83.     for (int i = 1;i <= n;++i) dp[i][1] = sum2[i] - sum3[i];  
  84.     for (int j = 2;j <= K;++j)  
  85.     {  
  86.         head = tail = 0;  
  87.         q[tail++] = 0;  
  88.         for (int i = 1;i <= n;++i)  
  89.         {  
  90.             while (head+1<tail&&dy(j,q[head+1],q[head])<=sum1[i]*dx(q[head+1],q[head])) ++head;  
  91.             dp[i][j] = DP(i,j,q[head]);  
  92.             while (head+1<tail&&dy(j,i,q[tail-1])*dx(q[tail-1],q[tail-2])<=dy(j,q[tail-1],q[tail-2])*dx(i,q[tail-1])) --tail;  
  93.             q[tail++] = i;  
  94.         }  
  95.     }   
  96.     return dp[n][K];  
  97. }  
  98. int kas;   
  99. int main()  
  100. {  
  101.     int T;Sint(T);  
  102.     while (T--)  
  103.     {  
  104.         init();  
  105.         printf("Case %d: %lld\n",++kas,solve());  
  106.     }  
  107.     return 0;  
  108. }  

14.HDU 3480 Division

  1. #define mem(a,x) memset(a,x,sizeof(a))  
  2. #include<iostream>  
  3. #include<cstdio>  
  4. #include<cstring>  
  5. #include<algorithm>  
  6. #include<queue>  
  7. #include<set>  
  8. #include<stack>  
  9. #include<cmath>  
  10. #include<map>  
  11. #include<stdlib.h>  
  12. #include<cctype>  
  13. #include<string>  
  14. #define Sint(n) scanf("%d",&n)  
  15. #define Sll(n) scanf("%I64d",&n)  
  16. #define Schar(n) scanf("%c",&n)  
  17. #define Schars(s) scanf("%s",s)   
  18. #define Sint2(x,y) scanf("%d %d",&x,&y)  
  19. #define Sll2(x,y) scanf("%I64d %I64d",&x,&y)  
  20. #define Pint(x) printf("%d",x)  
  21. #define Pllc(x,c) printf("%I64d%c",x,c)  
  22. #define Pintc(x,c) printf("%d%c",x,c)  
  23. using namespace std;  
  24. typedef long long ll;  
  25. const int inf = 0x3f3f3f3f;  
  26. /* 
  27.     dp[i][j]表示前i个字符分成j份的最小值 
  28.     d[i][j]表示 [i,j] 当成一份的花费  
  29.     dp[i][j] = dp[k][j-1] + d[k+1][j] 
  30.     but d[20000][20000]开不下。。。 
  31.     so 换个方法算d[i][j] 
  32.     sum1[i]表示前i个数的和 
  33.     sum2[i]表示 求和((i-1)*a[i]) 
  34.     sum3[i]表示 求和(a[i]*a[i]) 
  35.     故  
  36.     dp[i][j] = dp[k][j-1] + sum2[i] - sum2[k] - k*(sum1[i]-sum1[k]) - (sum3[i] - sum3[k]) 
  37.       
  38. */  
  39. const int N = 20004;  
  40. ll dp[N][504],sum1[N],sum2[N],sum3[N];  
  41. int a[N];  
  42. int mp[30];  
  43. char NP[30];  
  44. char NM[N];  
  45. int q[N],head,tail;  
  46. int K;  
  47. int n;  
  48. void init()  
  49. {  
  50.     Schars(NP);Sint(K);  
  51.     Schars(NM);  
  52.     for (int i = 0;i < strlen(NP);++i)  
  53.     {  
  54.         mp[NP[i] - 'a'] = i;   
  55.     }   
  56.     n = strlen(NM);  
  57.     for (int i = 0;i < n;++i)  
  58.     {  
  59.         a[i+1] = mp[NM[i] - 'a'];  
  60.     }  
  61.     for (int i = 1;i <= n;++i)  
  62.     {  
  63.         sum1[i] = sum1[i-1] + a[i];  
  64.         sum2[i] = sum2[i-1] + (i-1)*a[i];  
  65.         sum3[i] = sum3[i-1] + a[i]*a[i];  
  66.     }  
  67. }  
  68. //dp[i][j] = dp[k][j-1] + sum2[i] - sum2[k] - k*(sum1[i]-sum1[k]) - (sum3[i] - sum3[k])  
  69. ll DP(int i,int j,int k)  
  70. {  
  71.     return dp[k][j-1] + sum2[i] - sum2[k] - k*(sum1[i] - sum1[k]) - (sum3[i] - sum3[k]);  
  72. }  
  73. ll dy(int j,int q,int p)  
  74. {  
  75.     return dp[q][j-1]-dp[p][j-1] + q*sum1[q] - p*sum1[p] - (sum2[q]-sum2[p]) + (sum3[q]-sum3[p]);  
  76. }  
  77. ll dx(int q,int p)  
  78. {  
  79.     return q-p;  
  80. }  
  81. ll solve()  
  82. {  
  83.     for (int i = 1;i <= n;++i) dp[i][1] = sum2[i] - sum3[i];  
  84.     for (int j = 2;j <= K;++j)  
  85.     {  
  86.         head = tail = 0;  
  87.         q[tail++] = 0;  
  88.         for (int i = 1;i <= n;++i)  
  89.         {  
  90.             while (head+1<tail&&dy(j,q[head+1],q[head])<=sum1[i]*dx(q[head+1],q[head])) ++head;  
  91.             dp[i][j] = DP(i,j,q[head]);  
  92.             while (head+1<tail&&dy(j,i,q[tail-1])*dx(q[tail-1],q[tail-2])<=dy(j,q[tail-1],q[tail-2])*dx(i,q[tail-1])) --tail;  
  93.             q[tail++] = i;  
  94.         }  
  95.     }   
  96.     return dp[n][K];  
  97. }  
  98. int kas;   
  99. int main()  
  100. {  
  101.     int T;Sint(T);  
  102.     while (T--)  
  103.     {  
  104.         init();  
  105.         printf("Case %d: %lld\n",++kas,solve());  
  106.     }  
  107.     return 0;  

猜你喜欢

转载自blog.csdn.net/qq_27151549/article/details/80112893