考虑枚举加油的位置,当确定某次在第$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 }

最新文章

  1. D:Wordpress_AFC插件常用代码
  2. SQL Server 抛出自定义异常,由C#程序俘获之并进行相应的处理
  3. paip.提升用户体验--radio图片选择器 easyui 实现..
  4. linux 7 常见命令
  5. 基于Ascensor.js全屏切换页面插件
  6. PL/SQL Developer使用技巧
  7. Lucene.Net 2.3.1开发介绍 —— 三、索引(七)
  8. PhpStorm 超强语言模板的支持
  9. CRM 2013 切换显示语言
  10. 搜索广告与广告网络Demand技术-探索与利用
  11. fopen()函数中参数mode的取值
  12. cpsr当前程序状态寄存器
  13. winXP/win7/win10系统关闭445端口方法全攻略
  14. redis3.2.6 集群安装
  15. PCL+VS2010环境配置
  16. svn 删除svn项目命令
  17. C# 6.0:Exception Filter——带条件的异常处理
  18. eclipse中web项目没有run on server
  19. leetcode279
  20. oracle权限管理学习

热门文章

  1. bzoj2242,洛谷2485----SDOI2011计算器(exgcd,qsm,bsgs模板)
  2. SpringMVC 获得请求数据
  3. 详解python三大器——迭代器、生成器、装饰器
  4. 手把手教你写hexo博客
  5. SPI在JDBC中的运用
  6. 【UE4 插件】UnrealEnginePython 源码版编译、项目打包注意事项
  7. 零基础小白要如何跟好的学习嵌入式Linux
  8. Linux C语言链表你学会了吗?
  9. Swift-方法调度-类的普通方法底层探究
  10. UVM:6.2.3 sequencer 的grab 操作