Luogu6005 [USACO20JAN]Time is Mooney G 題解
阿新 • • 發佈:2021-07-22
第一眼看到題面時可能覺得需要用 dijstra 或分層圖之類,但注意到資料範圍很小(都是 \(\leqslant1000\)),因此考慮好寫的 DP。
首先當然需要使用鄰接表存圖。
不妨設 \(f_{i,j}\) 為第 \(i\) 天在第 \(j\) 個城市所獲利潤,易得狀態轉移方程:
\[f_{i,j}=\max(f_{i,j},f_{i-1,e[i].to}) \]但是這還沒完,還有兩個問題需要解決:
-
會以 \(T^2\times C\) 的速度扣錢。
不妨在每次外層迴圈後處理 \(ans\),有:
\[ans=\max(ans,f[i][1]-c\times i^2); \] -
外層迴圈沒有明確邊界。
最大是 \(1000\),以此為邊界即可。注意:有的人可能習慣設 \(N=1010\) ,這會導致 \(i=N\) 時 RE,應該 \(N-10\)。
View code:
#include<bits/stdc++.h> using namespace std; #define int long long #define ri register int #define il inline const int INF=0x7fffffff,N=1010; int n,m,c,ans=0; int v[N]; int cnt,head[N]; int f[N][N]; struct Edge{ int to,nxt; }e[N<<2]; il ll read(){ ll x=0,y=1; char c=getchar(); while(c<'0'||c>'9'){ if(c=='-') y=-1; c=getchar(); } while(c>='0'&&c<='9'){ x=x*10+c-'0'; c=getchar(); } return x*y; } il void add(int u,int v){ e[++cnt]=(Edge){v,head[u]}; head[u]=cnt; } signed main(){ memset(f,-1,sizeof(f)); n=read(),m=read(),c=read(); for(ri i=1;i<=n;i++) v[i]=read(); for(ri i=1;i<=m;i++){ int u=read(),v=read(); add(u,v);//有向圖 } f[0][1]=0; for(ri i=1;i<=N-10;i++){ for(ri j=1;j<=n;j++){ for(ri k=head[j];k;k=e[k].nxt){ if(~f[i-1][e[k].to]) f[i][j]=max(f[i][j],f[i-1][e[k].to]+v[j]); } } ans=max(ans,f[i][1]-(c*i*i)); } printf("%lld",ans); return 0; }