题目链接 n个城市之间有m条有向边,在第i个点处可以花费pi将油量变成ci,每走过一条道路,油量将减少1。给出q次查询,每给定初始的城市s和拥有的金钱p,问在经过路程不小于d的情况下,最多能剩下多少钱。
必然要预处理一些关于距离或者费用的东西,由于距离的范围太大,考虑预处理费用。
考虑dp[s][v]表示从s出发,花费v元所能走的最长距离,在每次查询的时候只需要在dp[s]中二分地查找即可。
状态转移方程为dp[s][v] = max(dp[t][v - p[i]] + dis[s][t]),其中dis[s][t]表示在s加油以后从s到t最长的距离。
考虑计算dis[s][t],用dist[s][t][h]表示从s到t走不超过h条路的最远距离,可以直接Floyd求出答案,但是这个数据范围会TLE。可以用倍增的方式预处理出dist[s][t][k],从s到t走不超过2的k次方条路的最远距离,然后就对于每个起点合并出dis[s][t]。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <map>
#include <vector>
#include <iostream>
#include <algorithm>
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;
const int maxn = 105;
const ll mod = 1000000007;
int s, t, d;
int n, m, c, q, a, b;
ll maze[maxn][maxn], x;
ll w[maxn], v[maxn], tmp[maxn][maxn][22];
ll dis[maxn][maxn], dp[maxn][maxn*maxn];
void init()
{
memset(maze,-1,sizeof(maze));
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= n;j++)
{
for(int k = 1;k <= n;k++)
tmp[i][j][k] = -INF;
dis[i][j] = -INF;
tmp[i][j][0] = -INF;
}
dis[i][i] = 0;
tmp[i][i][0] = 0;
}
}
int main()
{
scanf("%d%d%d%d", &n, &m, &c, &q);
for(int i = 1;i <= n;i++)
scanf("%I64d%I64d", &w[i], &v[i]);
init();
for(int i = 1;i <= m;i++)
{
scanf("%d%d%I64d", &a, &b, &x);
maze[a][b] = max(x, maze[a][b]);
}
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= n;j++)
if(maze[i][j] != -1) tmp[i][j][0] = maze[i][j];
}
for(int k = 1;k <= 18;k++)
{
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= n;j++)
{
for(int p = 1;p <= n;p++)
tmp[i][j][k] = max(tmp[i][j][k], tmp[i][p][k - 1] + tmp[p][j][k - 1]);
}
}
}
for(int i = 1;i <= n;i++)
{
ll r = min(1LL*c, v[i]);
for(int k = 18;k >= 0;k--)
{
if(!(r & (1LL<<k))) continue;
ll res[maxn];
for(int j = 1;j <= n;j++) res[j] = -INF;
for(int j = 1;j <= n;j++)
{
for(int p = 1;p <= n;p++)
res[j] = max(res[j], dis[i][p] + tmp[p][j][k]);
}
for(int j = 1;j <= n;j++)
dis[i][j] = res[j];
}
}
for(int j = 0;j <= n*n;j++)
{
for(int i = 1;i <= n;i++)
{
dp[i][j] = 0;
if(j < w[i]) continue;
for(int k = 1;k <= n;k++)
dp[i][j] = max(dp[i][j], dp[k][j - w[i]] + dis[i][k]);
}
}
for(int i = 1;i <= q;i++)
{
scanf("%d%d%d", &s, &t, &d);
int tp = lower_bound(dp[s] + 1, dp[s] + n*n + 1, d) - dp[s];
if(tp <= t) printf("%d\n", t - tp);
else printf("-1\n");
}
return 0;
}