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);
}