题目链接:https://www.luogu.com.cn/problem/P6772
n n n个点 m m m条边,每个城市有不同的愉悦值,从 1 1 1出发,要求经过 T T T的时间后回到点 1 1 1(不能原地停留。
特别的是有 k k k个美食节,在第 t i t_i ti个时刻如果在第 x i x_i xi个城市就可以额外获得 y i y_i yi的愉悦值,求路径上最大愉悦值
首先矩阵乘法变形后是可以求最长路的
之后之前有一道题目 [ P O I 2015 ] W Y C [POI2015]WYC [POI2015]WYC【矩阵乘法,倍增】和这题很像,因为边权最大只有5,所以可以将每个点分成 5 5 5个点就可以跑矩阵乘法了。这样有 250 250 250个点,跑一次矩阵乘法是 O ( 25 0 3 log T ) O(250^3\log T) O(2503logT),不考虑美食节的情况下可以过,但是如果有美食节时间复杂度就接近 O ( k ∗ 25 0 3 log T ) O(k*250^3\log T) O(k∗2503logT)显然不可过。
然后之前有一道 N O I O n l i n e NOI\ Online NOI Online的题目 N O I O n l i n e # 3 NOI\ Online \#3 NOI Online#3提高组魔法值正解是先预处理出 l o g T log T logT个矩阵然后再用向量乘矩阵
我们就得出了解法,我们先预处理使得 F i = A 2 i F_i=A^{2^i} Fi=A2i,然后这样我们用向量乘矩阵就是 O ( n 2 ) O(n^2) O(n2)的,之后每次做矩阵到每一个美食节,然后对于在那一天的情况加上一个愉悦值即可,可以通过本题。
时间复杂度 : O ( ( n w ) 3 log T + ( n w ) 2 k log T ) :O((nw)^3\log T+(nw)^2k\log T) :O((nw)3logT+(nw)2klogT)
#include
#include
#include
#define p(x,y) ((x)*5+(y))
#define ll long long
using namespace std;
const ll N=51;
struct matrix{
ll a[N*5][N*5];
}f[32];
struct node{
ll t,x,y;
}h[210];
ll n,m,T,k,tot,Size,a[N*5],p2[32],c[N*5];
matrix operator*(const matrix &a,const matrix &b){
matrix c;memset(c.a,0xcf,sizeof(c.a));
for(ll i=0;i<Size;i++)
for(ll j=0;j<Size;j++)
for(ll k=0;k<Size;k++)
c.a[i][j]=max(c.a[i][j],a.a[i][k]+b.a[k][j]);
return c;
}
void mul(matrix &b){
memcpy(c,a,sizeof(c));
memset(a,0xcf,sizeof(a));
for(ll i=0;i<Size;i++)
for(ll j=0;j<Size;j++)
a[j]=max(a[j],b.a[i][j]+c[i]);
return;
}
void power(ll b){
for(ll i=0;i<=tot;i++)
if(b&p2[i])mul(f[i]);
return;
}
bool cmp(node x,node y)
{return x.t<y.t;}
int main()
{
// freopen("delicacy.in","r",stdin);
// freopen("delicacy.out","w",stdout);
scanf("%lld%lld%lld%lld",&n,&m,&T,&k);
Size=n*5;
memset(f[0].a,0xcf,sizeof(f[0].a));
for(ll i=0;i<n;i++){
scanf("%lld",&c[i]);
for(ll j=0;j<4;j++)
f[0].a[p(i,j+1)][p(i,j)]=0;
}
for(ll i=1;i<=m;i++){
ll x,y,w;
scanf("%lld%lld%lld",&x,&y,&w);x--;y--;
f[0].a[p(x,0)][p(y,w-1)]=c[y];
}
p2[0]=1;
while(p2[tot]*2<=T){
tot++;p2[tot]=p2[tot-1]*2;
f[tot]=f[tot-1]*f[tot-1];
}
for(ll i=1;i<=k;i++)
scanf("%lld%lld%lld",&h[i].t,&h[i].x,&h[i].y),h[i].x--;
sort(h+1,h+1+k,cmp);
ll now=0;h[++k]=(node){T,0,0};
memset(a,0xcf,sizeof(a));a[0]=c[0];
for(ll i=1;i<=k;i++){
power(h[i].t-now);
a[p(h[i].x,0)]+=h[i].y;
now=h[i].t;
}
if(a[0]<0)printf("-1");
else printf("%lld",a[0]);
}