[关闭]
@ysner 2018-10-14T15:14:41.000000Z 字数 1967 阅读 2454

[HNOI2005]星际贸易

DP 单调队列


题面

要素太多,还是自己看吧

解析

如果要求贸易额最大,就相当于:
个物品(星球),每个物品价值为(每个星球能卖),现装入一个体积为(载重量为)的背包,最大化装入物品体积之和。
一个裸背包即可解决第一问。

并且我们可以顺手得出,达到该贸易额,必须要停靠哪些站。
(当然,为了维护和加油,应该还需要停靠另外一些站)

接下来要求利润最大,就是要求加油与维修的费用最少。
由于,所以状态只能设两维:
表示到第个星球时油量为的最小花费。

相关转移:
加油:直接即可。
维护:从前面停靠了的站转移过来(枚到最近那个必须停靠的星球就行)。
这样好像是的。。。

然后膜了一发,发现维护的转移过程可以用单调队列优化(先尾后进后首)。
很有道理啊。
于是就做完了。
复杂度

细节问题:混用、背包转移不全、单调队列入出队条件设错(应该以当前值为参照,而不是队列内)。

  1. #include<iostream>
  2. #include<cmath>
  3. #include<cstdio>
  4. #include<cstring>
  5. #include<cstdlib>
  6. #include<algorithm>
  7. #include<vector>
  8. #define ll long long
  9. #define re register
  10. #define il inline
  11. #define fp(i,a,b) for(re int i=a;i<=b;++i)
  12. #define fq(i,a,b) for(re int i=a;i>=b;--i)
  13. using namespace std;
  14. const int N=2500;
  15. int n,m,V,len,A[N],B[N],L[N],P[N],F[N],dp[N][N<<1],pos,ans1,ans2,Q[N<<1][N],h[N<<1],t[N<<1];
  16. bool vis[N];
  17. il int gi()
  18. {
  19. re int x=0,t=1;
  20. re char ch=getchar();
  21. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  22. if(ch=='-') t=-1,ch=getchar();
  23. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  24. return x*t;
  25. }
  26. il int max(re int x,re int y){return x>y?x:y;}
  27. il int min(re int x,re int y){return x<y?x:y;}
  28. int main()
  29. {
  30. n=gi();m=gi();V=min(gi(),2*n);len=gi();
  31. fp(i,1,n)
  32. {
  33. A[i]=gi();B[i]=gi();L[i]=gi();P[i]=gi();F[i]=gi();
  34. if(L[i]-L[i-1]>len) return puts("Poor Coke!"),0;
  35. }
  36. memset(dp,-63,sizeof(dp));dp[0][0]=0;
  37. fp(i,1,n)
  38. fp(j,0,m)
  39. {
  40. if(j>=A[i]) dp[i][j]=max(dp[i][j],dp[i-1][j-A[i]]+B[i]);
  41. dp[i][j]=max(dp[i][j],dp[i-1][j]);
  42. }
  43. fp(i,1,m) if(dp[n][pos]<dp[n][i]) pos=i;
  44. ans1=dp[n][pos];
  45. fq(i,n,1) if(dp[i][pos]!=dp[i-1][pos]) vis[i]=1,pos-=A[i];
  46. memset(dp,63,sizeof(dp));dp[0][V]=0;Q[V][t[V]++]=0;
  47. fp(i,1,n)
  48. fp(j,0,V)
  49. {
  50. if(P[i]&&j) dp[i][j]=min(dp[i][j],dp[i][j-1]+P[i]);
  51. if(h[j+2]<t[j+2]) dp[i][j]=min(dp[i][j],dp[Q[j+2][h[j+2]]][j+2]+F[i]);
  52. if(vis[i]) h[j]=t[j]=0;//can't avoid
  53. while(h[j]<t[j]&&dp[Q[j][t[j]-1]][j]>=dp[i][j]) --t[j];
  54. Q[j][t[j]++]=i;
  55. while(h[j]<t[j]&&L[i+1]-L[Q[j][h[j]]]>len) ++h[j];
  56. }
  57. pos=0;
  58. fp(i,1,V) if(dp[n][i]<dp[n][pos]) pos=i;
  59. ans2=dp[n][pos];
  60. if(ans2>1e9) return puts("Poor Coke!"),0;
  61. printf("%d %d\n",ans1,ans1-ans2);
  62. return 0;
  63. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注