【洛谷P6772】美食家
題目
題目連結:https://www.luogu.com.cn/problem/P6772
坐落在 Bzeroth 大陸上的精靈王國擊退地災軍團的入侵後,經過十餘年的休養生息,重新成為了一片欣欣向榮的樂土,吸引著八方遊客。小 W 是一位遊歷過世界各地的著名美食家,現在也慕名來到了精靈王國。
精靈王國共有 \(n\) 座城市,城市從 \(1\) 到 \(n\) 編號,其中城市 \(i\) 的美食能為小 W 提供 \(c_i\) 的愉悅值。精靈王國的城市通過 \(m\) 條單向道路連線,道路從 \(1\) 到 \(m\) 編號,其中道路 \(i\) 的起點為城市 \(u_i\) ,終點為城市 \(vi_\)
小 W 計劃在精靈王國進行一場為期 \(T\) 天的旅行,更具體地:他會在第 \(0\) 天從城市 \(1\) 出發,經過 \(T\) 天的旅行,最終在恰好第 \(T\) 天回到城市 \(1\) 結束旅行。由於小 W 是一位美食家,每當他到達一座城市時(包括第 \(0\) 天和第 \(T\) 天的城市 \(1\)),他都會品嚐該城市的美食並獲得其所提供的愉悅值,若小 W 多次到達同一座城市,他將獲得多次愉悅值
對於上圖,小 W 一種為期 \(11\) 天的可行旅遊方案為 \(1 \to 2 \to 1 \to 2 \to 3 \to 1\):
- 第 \(0\) 天,小 W 從城市 \(1\) 開始旅行,獲得愉悅值 \(1\) 並向城市 \(2\) 出發。
- 第 \(1\) 天,小 W 到達城市 \(2\),獲得愉悅值 \(3\) 並向城市 \(1\) 出發。
- 第 \(4\) 天,小 W 到達城市 \(1\),獲得愉悅值 \(1\) 並向城市 \(2\) 出發。
- 第 \(5\) 天,小 W 到達城市 \(2\)
- 第 \(7\) 天,小 W 到達城市 \(3\),獲得愉悅值 \(4\) 並向城市 \(1\) 出發。
- 第 \(11\) 天,小 W 到達城市 \(1\),獲得愉悅值 \(1\) 並結束旅行。
- 小 W 在該旅行中獲得的愉悅值之和為 \(13\)。
此外,精靈王國會在不同的時間舉辦 \(k\) 次美食節。具體來說,第 \(i\) 次美食節將於第 \(t_i\) 天在城市 \(x_i\) 舉辦,若小 W 第 \(t_i\) 天時恰好在城市 \(x_i\),那麼他在品嚐城市 \(x_i\) 的美食時會額外得到 \(y_i\) 的愉悅值。現在小 W 想請作為精靈王國接待使者的你幫他算出,他在旅行中能獲得的愉悅值之和的最大值。
思路
首先如果沒有美食節和路徑長度,那麼這道題就是裸的矩陣乘法。
我們發現這道題的邊權不超過 \(5\),所以考慮將每條邊拆成 \(5\) 條邊來跑,這樣還是相當於邊權為 \(1\),但是點的數量為 \(5n\leq 250\)。
此時如果沒有美食節,那麼仍然直接矩陣乘法即可。
加入了美食節後,顯然要在每兩個美食節中間用矩陣快速冪計算出這幾天的答案,然後加上美食節貢獻。
但是直接這樣做是 \(O(kn^3\log t)\) 的,不可接受。
發現每次都要計算兩次美食節之間的代價大量運算重複,所以可以先預處理出矩陣的 \(2^i\) 冪,然後每次 \(O(\log t)\) 倍增求出。
然後答案是一個 \(1\times n\) 的矩陣,向量乘矩陣的複雜度是 \(O(n^2)\) 的,這樣時間複雜度就被我們降到了 \(O(kn^2\log t)\)。
總時間複雜度 \(O(n^3\log t+kn^2\log t)\)。此處 \(n\) 等於原題中 \(5n\)。
程式碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=260,LG=30;
int n,m,t,k,tot,maxn,a[N];
int ID(int x,int y)
{
return y*n+x;
}
struct node
{
int t,x,a;
}b[N];
bool cmp(node x,node y)
{
return x.t<y.t;
}
struct Matrix
{
ll a[N][N];
Matrix() { memset(a,0xcf,sizeof(a)); }
friend Matrix operator *(const Matrix &a,const Matrix &b)
{
Matrix c;
for (int i=1;i<=maxn;i++)
for (int j=1;j<=tot;j++)
for (int k=1;k<=tot;k++)
c.a[i][j]=max(c.a[i][j],a.a[i][k]+b.a[k][j]);
return c;
}
}ans,f[LG+1];
Matrix fpow(Matrix a,int k)
{
for (int i=LG;i>=0;i--)
if (k&(1<<i)) a=a*f[i];
return a;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&t,&k);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
for (int j=0;j<4;j++)
f[0].a[ID(i,j)][ID(i,j+1)]=0;
}
tot=5*n;
for (int i=1,x,y,z;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
f[0].a[ID(x,z-1)][y]=a[y];
}
maxn=tot;
for (int i=1;i<=LG;i++)
f[i]=f[i-1]*f[i-1];
maxn=1;
for (int i=1;i<=k;i++)
scanf("%d%d%d",&b[i].t,&b[i].x,&b[i].a);
sort(b+1,b+1+k,cmp);
b[k+1].t=t;
ans.a[1][1]=a[1];
ans=fpow(ans,b[1].t);
for (int i=1;i<=k;i++)
{
ans.a[1][b[i].x]+=b[i].a;
ans=fpow(ans,b[i+1].t-b[i].t);
}
ll WYCtxdy=ans.a[1][1];
if (WYCtxdy<0) printf("-1");
else printf("%lld",WYCtxdy);
return 0;
}