美食家
$0x00$ 前置知识$max-add$矩阵:
其实可以理解为$floyd$,不过枚举顺序按照矩阵乘法枚举,记得赋值初始值的时候别忘记赋$-inf$
然后这个矩阵也满足矩阵乘法的结合律,因而可以使用快速幂优化递推
$0x01$ 暴力$dp$:
这个题$dp$很好想了,$dp[i][u]+c[v]=dp[i+w][v]$,第一维是时间,第二维是到那个点
关于美食节的处理就是看看转移过来的时候那个时间是否在$v$城市过了节,过了节的情况再加上$y[v]$
$0x02$ 矩阵加速:
按照原来的找合法路径个数的题一样,使用邻接矩阵作为转移矩阵
但是这道题比较烦的事每条边贡献的时间是不同的
可以想到和题目 迷路 很相似,可以使用拆点的思想,让每次转移层次都加一
我们设$u$拆出来的点(包括他自己)分别为$u_1,u_2,u_3,u_4,u_5$,那么对于一条边$(u,v,w)$,
可以拆成两段,一段是$u_1->u_w$,这一段边权值都是$0$,第二段是$u_w->v_1$,边权为$c_v$
这样会漏一个$1$号点,那么在答案矩阵上面给$ans[1][1]$赋值$c_1$即可
那么就可以直接对建好的$5*n$的矩阵转移$T$次乘上一个答案矩阵,答案就是$ans[1][1]$
这是不考虑美食节的情况。
$0x03$ 美食节处理:
考虑美食节不同时出现,我们将其按时间排序,那么可以得到$dp[t_i]=dp[t_{i-1}]*G^{t_i-t_{i-1}}+y[x]$
如果直接这么打,复杂度会超,考虑预处理出$G^{2^i}$,再进行二进制拆分计算,因为每次计算的$dp[]$是一个向量矩阵
所以最终的时间复杂度为$O((5n)^3\log T+(5n)^2k\log T)$
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 namespace AE86{ 5 inline int read(){ 6 int x=0,f=1;char ch=getchar(); 7 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 8 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f; 9 }inline void write(int x,char opt='\n'){ 10 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-'); 11 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x); 12 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);} 13 }using namespace AE86; 14 int n,m,k,T,cnt,id[55][6],c[55],dp[205]; 15 namespace Matrix{ 16 struct Ma{ 17 int s[255][255]; 18 Ma(){memset(s,-0x3f,sizeof(s));} 19 inline void pre(){for(int i=1;i<=cnt;i++)s[i][i]=0;} 20 Ma operator*(const Ma&x)const{ 21 Ma ans; 22 for(int i=1;i<=cnt;i++) 23 for(int j=1;j<=cnt;j++) 24 for(int k=1;k<=cnt;k++) 25 ans.s[i][j]=max(ans.s[i][j],s[i][k]+x.s[k][j]); 26 return ans; 27 } 28 };Ma g; 29 inline Ma ksm(Ma a,int b){ 30 Ma ans; ans.pre(); 31 for(;b;b>>=1,a=a*a) if(b&1) ans=ans*a; 32 return ans; 33 } 34 }using namespace Matrix; 35 Ma bit[30]; 36 struct festival{ 37 int t,x,y; 38 bool operator<(const festival&x)const{ 39 return t<x.t; 40 } 41 }fe[205]; 42 inline void trans(Ma& ans,int b){ 43 for(int i=0;i<30;i++) if(b&(1<<i)){ 44 Ma res; 45 for(int j=1;j<=cnt;j++) 46 for(int k=1;k<=cnt;k++) 47 res.s[1][j]=max(res.s[1][j],ans.s[1][k]+bit[i].s[k][j]); 48 ans=res; 49 } 50 } 51 namespace WSN{ 52 inline short main(){ 53 n=read(); m=read(); T=read(); k=read(); 54 for(int i=1;i<=n;i++){ 55 c[i]=read(); 56 for(int j=1;j<=5;j++) id[i][j]=++cnt; 57 for(int j=1;j<5;j++) g.s[id[i][j]][id[i][j+1]]=0; 58 } 59 for(int i=1,u,v,w;i<=m;i++){ 60 u=read(); v=read(); w=read(); 61 g.s[id[u][w]][id[v][1]]=c[v]; 62 } 63 Ma ans;ans.s[1][id[1][1]]=c[1];bit[0]=g; 64 for(int i=1;i<30;i++) bit[i]=bit[i-1]*bit[i-1]; 65 for(int i=1,t,x,y;i<=k;i++){ 66 t=read(); x=read(); y=read(); 67 fe[i]=(festival){t,x,y}; 68 } sort(fe+1,fe+k+1); 69 int last=0; 70 for(int i=1;i<=k;i++){ 71 trans(ans,fe[i].t-last); 72 if(ans.s[1][id[fe[i].x][1]]>=0) 73 ans.s[1][id[fe[i].x][1]]+=fe[i].y; 74 last=fe[i].t; 75 } 76 if(fe[k].t!=T) trans(ans,T-fe[k].t); 77 write(ans.s[1][id[1][1]]>=0?ans.s[1][id[1][1]]:-1); 78 return 0; 79 } 80 } 81 signed main(){return WSN::main();}