不算很难想。首先看到总钱数比较少,考虑 DP 出 fi,j 表示从 i 出发,已经在
考虑如何转移,注意到油量比较大,所有不可能把它记到状态里。那我们就枚举下一次在哪里加油:
其中 gi,k 表示从 i 走到
现在我们只需解决怎么预处理出 g 数组。
如果暴力把步数记到状态里
正解是倍增 floyd ,预处理出 hk,i,j 表示从 i 走到
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#include<queue>
#define Fir first
#define Sec second
#define mp(x,y) make_pair(x,y)
using namespace std;
inline char gc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
char ch=gc(); int res=0,ff=1;
while(!isdigit(ch)) ch=='-'?ff=-1:0, ch=gc();
while(isdigit(ch)) res=(res<<3)+(res<<1)+ch-'0', ch=gc();
return res*ff;
}
const int maxn=102,maxc=1005,maxe=1005;
int n,m,C,p[maxn],c[maxn],_test,ans;
int fir[maxn],w[maxe],nxt[maxe],son[maxe],tot;
void add(int x,int y,int z){
son[++tot]=y; w[tot]=z; nxt[tot]=fir[x]; fir[x]=tot;
}
int g[maxn][maxn],h[18][maxn][maxn],A[maxn],B[maxn];
int f[maxn][maxn*maxn],INF;
inline void DP(int S){
memset(A,192,sizeof(A)); A[S]=0;
for(int i=0;i<=16;i++) if((min(C,c[S])>>i)&1){
memset(B,192,sizeof(B));
for(int j=1;j<=n;j++) if(A[j]>INF)
for(int k=1;k<=n;k++) if(h[i][j][k]>INF)
B[k]=max(B[k],A[j]+h[i][j][k]);
memcpy(A,B,sizeof(B));
}
for(int i=1;i<=n;i++) g[S][i]=A[i];
}
int main(){
n=getint(); m=getint(); C=getint(); _test=getint();
for(int i=1;i<=n;i++) p[i]=getint(), c[i]=getint();
memset(h,192,sizeof(h)); INF=h[0][0][0];
for(int i=1;i<=n;i++) h[0][i][i]=0;
for(int i=1;i<=m;i++){
int x=getint(),y=getint(),z=getint();
add(x,y,z);
h[0][x][y]=max(h[0][x][y],z);
}
for(int k=1;k<=16;k++){
memcpy(h[k],h[k-1],sizeof(h[k]));
for(int l=1;l<=n;l++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) if(h[k-1][i][l]>INF&&h[k-1][l][j]>INF)
h[k][i][j]=max(h[k][i][j],h[k-1][i][l]+h[k-1][l][j]);
}
for(int i=1;i<=n;i++) DP(i);
for(int j=0;j<=n*n;j++)
for(int i=1;i<=n;i++) for(int k=1;k<=n;k++) f[i][j]=max(f[i][j],g[i][k]);
for(int j=1;j<=n*n;j++)
for(int i=1;i<=n;i++) // f[i][j] µ±Ç°ÔÚi,ÒѾԵؼÓÁËÓÍ£¬ Ê£ÏÂj¿éÇ®
for(int k=1;k<=n;k++)
if(j>=p[k]) f[i][j]=max(f[i][j],f[k][j-p[k]]+g[i][k]);
while(_test--){
int s=getint(),q=getint(),d=getint();
ans=-1;
int L=p[s],R=q;
while(L<=R){
int mid=(L+R)>>1;
if(f[s][mid-p[s]]>=d) R=mid-1, ans=q-mid;
else L=mid+1;
}
printf("%d\n",max(-1,ans));
}
return 0;
}