1. 程式人生 > 實用技巧 >[loj3339]美食家

[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)
 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 }
View Code