神\(TM\)的超多信息。。。spa
認真觀察一波題面,咱們發現第一問就是個揹包,跑一遍就行了。code
狀態爲\(f[i][j]\)表示前\(i\)個星球,賣了\(j\)噸的最大貿易額。隊列
可是在第一問中的最優答案和第二問有關,具體來講是第一問中的中轉移的點必選。get
關於第二問,咱們設\(f[i][j]\)表示到第\(i\)個星球,剩餘\(j\)個燃料的最小花費。博客
根據買燃料和維修兩種狀況轉移就行了。it
\(f[i][j]=max(f[i][j-1]+P_i,f[k][j+2]+F_i)\)class
顯然這個轉移是\(n^3\)的,咱們經過\(yyb\)的博客發現有單調性,用單調隊列維護便可。數據
注意遇到第一問中必須轉移的點時隊列清空。di
#include<bits/stdc++.h> using namespace std; #define int long long inline int read() { int f=1,w=0;char x=0; while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();} while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();} return w*f; } const int N=2e3+10; int n,MF,ML,m,J,JJ,Q[N<<1][N]; int f[N][N<<1],Vis[N<<1],H[N<<1],T[N<<1]; struct Planet { int Out,Mon; int Dis,Amt,Fix; } p[N]; signed main(){ #ifndef ONLINE_JUDGE freopen("A.in","r",stdin); #endif n=read();m=read(),MF=read(),ML=read(); if(MF>(n<<1)) MF=n<<1; for(int i=1;i<=n;i++) { p[i].Out=read(),p[i].Mon=read(); p[i].Dis=read(),p[i].Amt=read(),p[i].Fix=read(); } for(int i=1;i<=n;i++) if(p[i].Dis-p[i-1].Dis>ML){puts("Poor Coke!");return 0;} memset(f,0xf3,sizeof(f));f[0][0]=0; for(int i=1;i<=n;i++) for(int j=0;j<=m;j++) { if(j>=p[i].Out) f[i][j]=max(f[i-1][j],f[i-1][j-p[i].Out]+p[i].Mon); f[i][j]=max(f[i-1][j],f[i][j]); } for(int i=1;i<=m;i++) if(f[n][i]>f[n][J]) J=i; int MYE=f[n][J]; for(int i=n,Now=J;i;i--) if(f[i][Now]!=f[i-1][Now]) Vis[i]=1,Now-=p[i].Out; memset(f,0x3f,sizeof(f)); f[0][MF]=0;Q[MF][T[MF]++]=0; //H[MF]=1; for(int i=1;i<=n;i++) for(int j=0;j<=MF;j++) { if(p[i].Amt&&j) f[i][j]=min(f[i][j],f[i][j-1]+p[i].Amt); if(T[j+2]>H[j+2]) f[i][j]=min(f[i][j],f[Q[j+2][H[j+2]]][j+2]+p[i].Fix); if(Vis[i]) H[j]=0,T[j]=0; while(H[j]<T[j]&&f[Q[j][T[j]-1]][j]>=f[i][j]) T[j]--; Q[j][T[j]++]=i; while(H[j]<T[j]&&p[i+1].Dis-p[Q[j][H[j]]].Dis>ML) H[j]++; } for(int j=1;j<=MF;j++) if(f[n][j]<f[n][JJ]) JJ=j; f[n][JJ]>=1e9?puts("Poor Coke!"):printf("%lld %lld",MYE,MYE-f[n][JJ]); }