「LibreOJ NOIP Round #1」旅游路线
这道题真的好棒啊.. 不愧是WA爷出的题啊
题目大意
有$n$个点$m$条有向边,在每个点可以花$p_i$的钱加油至$min(C,c_i)$,每经过一条边会耗费$1$的油量
给出$T$个询问,每次询问从$s$出发,$q$块钱,走$d$的路程最多剩下多少钱
我好菜啊..
只能想到设$f_{i,q,c}$为走到$i$节点剩下$q$块钱还有$c$油量的最大路程来dp..
但是没法摆脱油量的限制
题解的做法很棒
就是设$f_{i,q}$为走到$i$节点并且在这里加油还剩下$q$块钱的最大路程,然后枚举下一次加油的地方来dp
那问题现在就转化为求从$i$到$j$不经过$min(C,c_i)$条边的最大路程
然后发现这个东西可以倍增求就很棒了
code
#include#include #include #include #define LL long long using namespace std; const LL Maxn = 110; const LL Maxp = 100010; const LL lg = 17; const LL inf = (LL)1<<60; LL f[Maxn][Maxn*Maxn]; LL g[lg][Maxn][Maxn]; LL w[Maxn][Maxn]; LL n, m, C, T; LL p[Maxn], c[Maxn]; LL bit[Maxp]; LL A[Maxn], B[Maxn]; LL _max(LL x, LL y) { return x > y ? x : y; } LL _min(LL x, LL y) { return x < y ? x : y; } int main() { LL i, j, k; scanf("%lld%lld%lld%lld", &n, &m, &C, &T); for(i = 1; i <= n; i++) for(j = 1; j <= n; j++) g[0][i][j] = i == j ? 0 : -inf; for(i = 1; i <= n; i++) scanf("%lld%lld", &p[i], &c[i]); for(i = 1; i <= m; i++){ LL x, y, d; scanf("%lld%lld%lld", &x, &y, &d); g[0][x][y] = _max(g[0][x][y], d); } for(LL x = 1; x < lg; x++){ for(i = 1; i <= n; i++) for(j = 1; j <= n; j++) g[x][i][j] = -inf; for(k = 1; k <= n; k++){ for(i = 1; i <= n; i++){ for(j = 1; j <= n; j++) g[x][i][j] = _max(g[x][i][j], g[x-1][i][k]+g[x-1][k][j]); } } } for(i = 2; i <= 100000; i++) bit[i] = bit[i>>1]+1; for(i = 1; i <= n; i++){ for(j = 1; j <= n; j++) A[j] = i == j ? 0 : -inf; LL u = _min(C, c[i]); for(int x = 0; x < lg; x++){ if(u&(1< >1; if(f[s][mid] >= d){ ret = mid; R = mid-1; } else L = mid+1; } printf("%lld\n", q-ret); } return 0; }