luogu P5052 [COCI2017-2018#7] Go
阿新 • • 發佈:2021-06-12
題面傳送門
不知道這道題為什麼有紫題難度,隨便寫寫就過了。
容易想到dp解決這個問題。
我們設\(f_{i,j,t,0/1}\)表示當前經過了\([i,j]\)區間內的小精靈,經過了\(t\)的時間,在左/右端點能得到的最大收益。
這個東西隨便從左右轉移一下即可。
然後你會發現這個東西是\(O(n^2MaxT)\)的很屑過不去。
可以發現實際上只有\(m\)的點是有用的,而\(m\)的規模遠小於\(n\),所以把\(m\)離散化一下記錄距離,再將起點作為特殊點放進去即可。
注意特判起點是不是和一個特殊點重合不然會WA一個點。
時間複雜度\(O(m^2MaxT)\)
code:
#include <vector> #include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<cmath> #include<algorithm> #include<bitset> #include<set> #include<map> #define I inline #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define abs(x) ((x)>0?(x):-(x)) #define l(x) x<<1 #define r(x) x<<1|1 #define re register #define ll long long #define db double #define N 100 #define M 2000 #define eps (1e-5) #define mod (1<<31) #define U unsigned int using namespace std; int n,m,k,dp[N+5][N+5][M+5][2],flag,Maxn,Ans,Pus,now; struct yyy{int A,T,B;}S[N+5]; I bool cmp(yyy x,yyy y){return x.A<y.A;} int main(){ freopen("1.in","r",stdin); re int i,j,h;scanf("%d%d%d",&n,&k,&m);for(i=1;i<=m;i++) scanf("%d%d%d",&S[i].A,&S[i].B,&S[i].T),Maxn=max(Maxn,S[i].T); for(i=1;i<=m;i++) if(S[i].A==k){flag=1;break;}!flag&&(S[++m]=(yyy){k,0,0},0);sort(S+1,S+m+1,cmp); memset(dp,-0x3f,sizeof(dp));for(i=1;i<=m;i++) S[i].A==k&&(dp[i][i][0][0]=dp[i][i][0][1]=S[i].B); for(i=m;i;i--){ for(j=i+1;j<=m;j++){ now=S[i+1].A-S[i].A;for(h=now;h<=Maxn;h++)dp[i][j][h][0]=max(dp[i][j][h][0],dp[i+1][j][h-now][0]+(h<S[i].T?S[i].B:0)); now=S[j].A-S[i].A;for(h=now;h<=Maxn;h++) dp[i][j][h][0]=max(dp[i][j][h][0],dp[i+1][j][h-now][1]+(h<S[i].T?S[i].B:0));dp[i][j][h][0]=Ans; now=S[j].A-S[j-1].A;for(h=now;h<=Maxn;h++) dp[i][j][h][1]=max(dp[i][j][h][1],dp[i][j-1][h-now][1]+(h<S[j].T?S[j].B:0)); now=S[j].A-S[i].A;for(h=now;h<=Maxn;h++) dp[i][j][h][1]=max(dp[i][j][h][1],dp[i][j-1][h-now][0]+(h<S[j].T?S[j].B:0));dp[i][j][h][1]=Ans; for(h=1;h<=Maxn;h++) Ans=max(Ans,max(dp[i][j][h][1],dp[i][j][h][0])); } } printf("%d\n",Ans); }