CF1932G 题解

思路

首先这题要用最短路是显然的,但是边权不固定(但对 dijkstra 过程没影响,因为边权没有负数)。在做 dijkstra 的时候,我们的边权取决于不固定的当前高度和固定的增长高度,然后类似 P1516 用 exgcd 把边权算出来松弛即可。

注意事项

请及时取模,否则在乘法和 exgcd 时会爆 long long

代码

# include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair <int, int> pii;
const ll inf = 1e18;
struct node {
	int x;
	ll dis;
	bool operator < (const node& t) const {
		return dis > t.dis;
	}
} ;
ll exgcd (ll a, ll b, ll& x, ll& y) {
	if (! b) {
		x = 1, y = 0;
		return a;
	}
	ll g = exgcd (b, a % b, x, y), tmp = x;
	x = y, y = tmp - a / b * y;
	return g;
}
int t, n, m, x, y;
ll h, l[100005], s[100005], dis[100005], a, b, w, ans1, ans2, g;
vector <int> v[100005];
priority_queue <node> q;
ll exg (ll a, ll b, ll c) {
	if (a < 0)
		a = -a, c = -c;
	g = exgcd (a, b, ans1, ans2);
	if (c % g)
		return inf;
	b /= g, c /= g;
	return (ans1 * c % b + b) % b;
}
ll bfs () {
	fill (dis + 2, dis + n + 1, inf);
	q.push ({1, 0});
	while (! q.empty ()) {
		node t = q.top ();
		if (t.x == n) {
			while (! q.empty ())
				q.pop ();
			return t.dis;
		}
		q.pop ();
		if (t.dis > dis[t.x])
			continue ;
		for (int& i : v[t.x]) {
			w = exg (s[i] - s[t.x], h, (t.dis % h * (s[t.x] - s[i]) + l[t.x] - l[i]) % h) + 1;
			if (t.dis + w < dis[i])
				q.push ({i, dis[i] = t.dis + w});
		}
	}
	return -1;
}
int main () {
	ios::sync_with_stdio (0);
	cin.tie (0);
	cout.tie (0);
	cin >> t;
	while (t --) {
		cin >> n >> m >> h;
		for (int i = 1; i <= n; ++ i)
			cin >> l[i], v[i].clear ();
		for (int i = 1; i <= n; ++ i)
			cin >> s[i];
		while (m --) {
			cin >> x >> y;
			v[x].emplace_back (y);
			v[y].emplace_back (x);
		}
		cout << bfs () << '\n';
	}
	return 0;
}
posted @ 2024-05-22 13:18  Vitamin_B  阅读(11)  评论(0)    收藏  举报  来源