Loading

美食家

$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();}
美食家

 

posted @ 2021-10-01 21:34  雪域亡魂  阅读(48)  评论(0编辑  收藏  举报