[loj3339]美食家
令$f[i][j]$表示第$i$个时刻走到点$j$的最小时间,暴力的$dp$复杂度为$o(tm)$
如果没有限制,由于$w\le 5$,记录前5个时刻的状态即可求出当前状态,用矩阵乘法可优化到$o(n^{3}\log_{2}T)$
当$k\le 10$时,考虑特殊的转移只有10个位置,对于其他位置矩乘转移,这些位置特殊考虑,复杂度$o(n^{3}k\log_{2}T)$
用倍增预处理出矩阵的$2^{i}$次幂,直接用答案进行运算使一次乘法降为$o(n^{2})$,总复杂度即$o((n+k)n^2\log_{2}T)
View Code
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define oo 1e15 5 struct mat{ 6 ll a[305][305]; 7 }a,o,aa,mi[31]; 8 struct fe{ 9 int t,k,w; 10 }b[205]; 11 int n,m,t,k,x,y,z,flag,w[105]; 12 ll s[305],ans[305]; 13 bool cmp(fe x,fe y){ 14 return x.t<y.t; 15 } 16 mat mul(mat &x,mat &y){ 17 for(int i=1;i<=5*n;i++) 18 for(int j=1;j<=5*n;j++){ 19 o.a[i][j]=-oo; 20 for(int k=1;k<=5*n;k++)o.a[i][j]=max(o.a[i][j],x.a[i][k]+y.a[k][j]); 21 } 22 return o; 23 } 24 void mul(mat &x){ 25 memcpy(s,ans,sizeof(s)); 26 for(int i=1;i<=5*n;i++){ 27 ans[i]=-oo; 28 for(int j=1;j<=5*n;j++)ans[i]=max(ans[i],s[j]+x.a[j][i]); 29 } 30 } 31 void pow(int n){ 32 for(int i=0;i<=30;i++) 33 if (n&(1<<i))mul(mi[i]); 34 } 35 int main(){ 36 freopen("delicacy.in","r",stdin); 37 freopen("delicacy.out","w",stdout); 38 scanf("%d%d%d%d",&n,&m,&t,&k); 39 for(int i=1;i<=n;i++)scanf("%d",&w[i]); 40 for(int i=1;i<=5*n;i++) 41 for(int j=1;j<=5*n;j++)a.a[i][j]=-oo; 42 for(int i=1;i<=m;i++){ 43 scanf("%d%d%d",&x,&y,&z); 44 a.a[(5-z)*n+x][4*n+y]=w[y]; 45 } 46 for(int i=n+1;i<=5*n;i++)a.a[i][i-n]=0; 47 aa=a; 48 for(int i=1;i<=k;i++)scanf("%d%d%d",&b[i].t,&b[i].k,&b[i].w); 49 sort(b+1,b+k+1,cmp); 50 mi[0]=a; 51 for(int i=1;i<=30;i++)mi[i]=mul(mi[i-1],mi[i-1]); 52 for(int i=1;i<=5*n;i++)ans[i]=-oo; 53 ans[4*n+1]=0; 54 for(int i=1;i<=k;i++){ 55 pow(b[i].t-b[i-1].t-1); 56 a=mi[0]; 57 for(int j=1;j<=5*n;j++)a.a[j][4*n+b[i].k]+=b[i].w; 58 mul(a); 59 } 60 pow(t-b[k].t); 61 if (ans[4*n+1]<0)printf("-1\n"); 62 else printf("%lld",ans[4*n+1]+w[1]); 63 return 0; 64 }