前言
我考场(线上赛)切NOI的题了!
正题
题目链接:https://www.luogu.com.cn/problem/P6772
题目大意
nnn个点mmm条边,每个城市有不同的愉悦值,从111出发,要求经过TTT的时间后回到点111(不能原地停留。
特别的是有kkk个美食节,在第tit_iti个时刻如果在第xix_ixi个城市就可以额外获得yiy_iyi的愉悦值,求路径上最大愉悦值
解题思路
首先矩阵乘法变形后是可以求最长路的
之后之前有一道题目[POI2015]WYC[POI2015]WYC[POI2015]WYC【矩阵乘法,倍增】和这题很像,因为边权最大只有5,所以可以将每个点分成555个点就可以跑矩阵乘法了。这样有250250250个点,跑一次矩阵乘法是O(2503logT)O(250^3\log T)O(2503logT),不考虑美食节的情况下可以过,但是如果有美食节时间复杂度就接近O(k∗2503logT)O(k*250^3\log T)O(k∗2503logT)显然不可过。
然后之前有一道NOIOnlineNOI\ OnlineNOI Online的题目NOIOnline#3NOI\ Online \#3NOI Online#3提高组魔法值正解是先预处理出logTlog TlogT个矩阵然后再用向量乘矩阵
我们就得出了解法,我们先预处理使得Fi=A2iF_i=A^{2^i}Fi=A2i,然后这样我们用向量乘矩阵就是O(n2)O(n^2)O(n2)的,之后每次做矩阵到每一个美食节,然后对于在那一天的情况加上一个愉悦值即可,可以通过本题。
时间复杂度:O((nw)3logT+(nw)2klogT):O((nw)^3\log T+(nw)^2k\log T):O((nw)3logT+(nw)2klogT)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#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]);
}