1. 程式人生 > 其它 >luogu P6772 [NOI2020] 美食家

luogu P6772 [NOI2020] 美食家

題面傳送門
這麼小的\(n\),這麼大的\(T\)肯定是矩陣快速冪的節奏。
我們考慮這個邊的時間怎麼處理。
因為時間是真的小,所以我們可以將每個點拆成\(5\)個點,然後由每個點的第\(w\)個點向那邊的點連邊。
然後這個美食節我們可以拆成\(k+1\)段,每一段直接矩陣快速冪,中間乘上特殊矩陣。
然後我們發現這個東西是\(O(k(5n)^3logT)\)的過不去。
我們只要\(A_{1,1}\),所以可以參照那道NOI online只儲存第一行的那個向量然後每次向量和矩陣相乘就少一個\(5n\)
預處理2的冪次矩陣就變成了\(O((5n)^3logT+k(5n)^2logT)\)
code:

#include<bits/stdc++.h>
#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 re register
#define ll long long
#define db double
#define N 250
#define M 200000
#define mod 998244353
#define eps (1e-5)
#define U unsigned int
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
using namespace std;
int n,m,k,T,x,y,z,W[N+5];
struct matrix{
	ll A[N+5][N+5];
	matrix(){Me(A,-0x3f);}
	matrix operator *(const matrix &B)const{
		matrix C;re int i,j,h;for(i=1;i<=5*n;i++){
			for(j=1;j<=5*n;j++){
				for(h=1;h<=5*n;h++) C.A[i][j]=max(C.A[i][j],A[i][h]+B.A[h][j]);
			} 
		}return C;
	}
}bas[40],G;
struct vecto{
	ll A[N+5];
	vecto(){Me(A,-0x3f);}
	vecto operator *(const matrix &B)const{
		vecto C;re int i,j;for(i=1;i<=5*n;i++){
			for(j=1;j<=5*n;j++) C.A[i]=max(C.A[i],A[j]+B.A[j][i]);
		}return C;
	}
}Ans;
struct ques{int T,x,y;}S[N+5];I bool cmp(ques x,ques y){return x.T<y.T;}
int main(){
	freopen("1.in","r",stdin);
	re int i,j;scanf("%d%d%d%d",&n,&m,&T,&k);for(i=1;i<=n;i++) scanf("%d",&W[i]);for(i=1;i<=m;i++) scanf("%d%d%d",&x,&y,&z),G.A[(x-1)*5+z][(y-1)*5+1]=W[y];
	for(i=1;i<=n;i++) for(j=5*(i-1)+1;j<5*i;j++)G.A[j][j+1]=0; 
	bas[0]=G;for(i=1;i<=30;i++)bas[i]=bas[i-1]*bas[i-1]; for(i=1;i<=k;i++)scanf("%d%d%d",&S[i].T,&S[i].x,&S[i].y);sort(S+1,S+k+1,cmp);Ans.A[1]=W[1];
	for(i=1;i<=k;i++){
		x=S[i].T-S[i-1].T-1;for(j=30;~j;j--) (x>>j)&1&&(Ans=Ans*bas[j],0);for(j=1;j<=5*n;j++) G.A[j][5*(S[i].x-1)+1]+=S[i].y;Ans=Ans*G;for(j=1;j<=5*n;j++) G.A[j][5*(S[i].x-1)+1]-=S[i].y;
	}x=T-S[k].T;for(i=30;~i;i--) (x>>i)&1&&(Ans=Ans*bas[i],0);
	/*for(i=1;i<=x;i++) 
	Ans=Ans*G;*/
	printf("%lld\n",(Ans.A[1]>=0)?Ans.A[1]:-1);
}