NOI真题解答201
本题与矩阵乘法有关,考虑矩阵乘法的性质,需满足乘法交换律与加乘结合律,(加法交换律可由这两个定律推出)
在本题中,取max为广义加法,加法为广义乘法,定义矩阵乘法,考虑分5层建图
考虑对矩阵预处理,不过还是kn^3,最后只需要第一行的矩阵,这样从最左边开始,只保留第一行,每次只需n^2,一共有k段,每两段之间二进制拆分,kn^2log(n)
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=255;
const int inf=0x3f3f3f3f3f3f3f3fll;
int n;
struct M{
int d[N][N];
M operator*(const M &R)const {
M ret;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) {
ret.d[i][j]=-inf;
for(int k=1;k<=n;k++)
ret.d[i][j]=max(ret.d[i][j],d[i][k]+R.d[k][j]);
}
return ret;
}
}X[35],G;
int T,K;
int c[N];
int t[N],x[N],y[N];
int b[N],tmp[N];
int m;
void mul(M Y) {
for(int i=1;i<=n;i++) {tmp[i]=b[i];b[i]=-inf;}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) {
b[i]=max(b[i],tmp[j]+Y.d[j][i]);
}
}
signed main() {
cin>>n>>m>>T>>K;
for(int i=1;i<=n;i++) scanf("%lld",&c[i]);
for(int i=1;i<=5*n;i++)
for(int j=1;j<=5*n;j++)
X[0].d[i][j]=-inf;
for(int i=1;i<=n;i++)
for(int j=1;j<=4;j++)
X[0].d[i+n*j][i+n*(j-1)]=0;
for(int i=1;i<=m;i++) {
int u,v,w;
scanf("%lld%lld%lld",&u,&v,&w);
X[0].d[v][u+n*(w-1)]=c[v];
}
n*=5;
for(int i=1;i<=30;i++) X[i]=X[i-1]*X[i-1];
for(int i=1;i<=K;i++) scanf("%lld%lld%lld",&t[i],&x[i],&y[i]);
for(int i=1;i<=K;i++)
for(int j=i+1;j<=K;j++) {
if(t[i]<t[j]) {
swap(t[i],t[j]);
swap(x[i],x[j]);
swap(y[i],y[j]);
}
}
for(int i=2;i<=n;i++) b[i]=-inf;
int z=T-t[1];
for(int k=0;k<=30;k++)
if((z>>k)&1) mul(X[k]);
for(int i=1;i<=K;i++) {
G=X[0];
for(int j=1;j<=n;j++)
G.d[x[i]][j]+=y[i];
mul(G);
int z=t[i]-t[i+1]-1;
for(int k=0;k<=30;k++)
if((z>>k)&1) mul(X[k]);
}
cout<<max(c[1]+b[1],-1ll)<<endl;
return 0;
}