[loj539]旅游路线

考虑枚举加油的位置,当确定某次在第$i$个位置加油后,且下一次到$j$加油,那么$i$到$j$必然会选择不超过$c_{i}$条边且最长的路径,记作$d_{i,j}$

如果能求出$d_{i,j}$,再设$f_{q,i}$表示$q$元(恰好用完)从$i$出发的最长路,枚举$i$之后那一次加油点即可转移,由于$q\le n^{2}$,因此这里的复杂度为$o(n^{4})$

接下来,对其求一次前缀max再二分,即可对询问做到$o(t\log_{2}q)$的复杂度

现在还有一个问题,考虑如何预处理最开始的$d_{i,j}$

倍增,求出从$i$出发,走不超过$2^{k}$次走到$j$的最长路,通过枚举走$2^{k-1}$时的点来转移,可以做到$o(n^{3}\log_{2}c_{i})$

类似的,再对每一个点$i$做一次dp,同样枚举中专点转移即可,时间复杂度也是$o(n^{3}\log_{2}c_{i})$

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 105
 4 #define M 1005
 5 #define K 100005
 6 struct ji{
 7     int nex,to,len;
 8 }edge[M];
 9 struct qu{
10     int s,q,d;
11 }q[K];
12 int E,n,m,t,x,y,z,head[N],p[N],c[N],g[21][N][N],ff[N],f[N][N],ans[N*N][N];
13 void add(int x,int y,int z){
14     edge[E].nex=head[x];
15     edge[E].to=y;
16     edge[E].len=z;
17     head[x]=E++;
18 }
19 int main(){
20     scanf("%d%d%d%d",&n,&m,&c[0],&t);
21     for(int i=1;i<=n;i++){
22         scanf("%d%d",&p[i],&c[i]);
23         c[i]=min(c[i],c[0]);
24         if (!p[i]){
25             printf("orz");
26             return 0;
27         }
28     }
29     memset(head,-1,sizeof(head));
30     for(int i=1;i<=m;i++){
31         scanf("%d%d%d",&x,&y,&z);
32         add(x,y,z);
33     }
34     memset(g,-0x3f,sizeof(g));
35     for(int i=1;i<=n;i++){
36         g[0][i][i]=0;
37         for(int j=head[i];j!=-1;j=edge[j].nex)g[0][i][edge[j].to]=max(g[0][i][edge[j].to],edge[j].len);
38     }
39     for(int i=1;i<=20;i++)
40         for(int x=1;x<=n;x++)
41             for(int y=1;y<=n;y++)
42                 for(int z=1;z<=n;z++)
43                     g[i][x][y]=max(g[i][x][y],g[i-1][x][z]+g[i-1][z][y]);
44     memset(f,-1,sizeof(f));
45     for(int i=1;i<=n;i++)f[i][i]=0;
46     for(int x=1;x<=n;x++)
47         for(int i=0;i<=20;i++)
48             if (c[x]&(1<<i)){
49                 for(int y=1;y<=n;y++)ff[y]=f[x][y];
50                 for(int y=1;y<=n;y++)
51                     for(int z=1;z<=n;z++)
52                         if (ff[z]!=-1)f[x][y]=max(f[x][y],ff[z]+g[i][z][y]);
53             }
54     memset(ans,-0x3f,sizeof(ans));
55     for(int i=1;i<=n;i++)ans[0][i]=0;
56     for(int i=1;i<=n*n;i++)
57         for(int x=1;x<=n;x++)
58             if (p[x]<=i)
59                 for(int y=1;y<=n;y++)
60                     if (f[x][y]!=-1)ans[i][x]=max(ans[i][x],ans[i-p[x]][y]+f[x][y]);//o(n^4)
61     for(int i=1;i<=n*n;i++)
62         for(int j=1;j<=n;j++)ans[i][j]=max(ans[i][j],ans[i-1][j]);
63     for(int i=1;i<=t;i++){
64         scanf("%d%d%d",&x,&y,&z);
65         if (ans[y][x]<z)printf("-1\n");
66         else{
67             int l=0,r=y;
68             while (l<r){
69                 int mid=(l+r>>1);
70                 if (ans[mid][x]>=z)r=mid;
71                 else l=mid+1;
72             }
73             printf("%d\n",y-l);
74         }
75     }
76     return 0;
77 }
View Code

 

posted @ 2021-01-21 15:31  PYWBKTDA  阅读(107)  评论(0编辑  收藏  举报