[算法学习] 同余最短路

对于一些形如询问$$\sum_{i = 1} ^ n a_i \times p_i = k$$的整数解或者有解的情况时,常常使用同余最短路的解法。

我们令\(dis_i\)记录凑出\(\bmod base\)余i最小的数是多少

然后可以用\(\text{dijkstra}\)的方法转移

\(f((x + y) \bmod base) = f(x) + y\)

墨墨的等式

const int N = 12 + 5;
const int M = 5e5 + 7;

int n, E, a[N], head[M];
ll l, r, ans;

struct EDGE {
	int w, to, nxt;
} edge[M * 12];

inline void addedge(int u, int v, int w) {
	edge[++E].to = v;
	edge[E].w = w;
	edge[E].nxt = head[u];
	head[u] = E;
}

namespace DIJKSTRA {

ll dis[M];

struct Node {
	ll u, d;
	Node(int U = 0, ll D = 0) {
		u = U; d = D;
	}
	bool operator < (const Node&rhs) const {
		return d > rhs.d;
	}
};	
	
priority_queue < Node > q;

inline void dijkstra() {
	for(int i = 0; i < a[0]; i++) dis[i] = INF;
	while(q.size()) q.pop();
	q.push(Node(0, 0)); dis[0] = 0;
	while(!q.empty()) {
		Node t = q.top(); q.pop();
		ll u = t.u, d = t.d;
		if(d != dis[u]) continue;
		for(int i = head[u]; i; i = edge[i].nxt) {
			ll v = edge[i].to, w = edge[i].w;
			if(dis[u] != INF && dis[v] > dis[u] + w) {
				dis[v] = dis[u] + w;
				q.push(Node(v, dis[v]));
			}
		}
	}
}

}

int main() {
	read(n); read(l); read(r);
	for(int i = 0; i < n; i++) read(a[i]);
	sort(a, a + n);
	for(int i = 0; i < a[0]; i++) {
		for(int j = 1; j < n; j++) {
			addedge(i, (i + a[j]) % a[0], a[j]);
		}
	}
	DIJKSTRA::dijkstra();
	for(int i = 0; i < a[0]; i++) {
		ll lans = 0, rans = 0;
		if(l - 1 >= DIJKSTRA::dis[i]) lans = (l - 1 - DIJKSTRA::dis[i]) / a[0] + 1;
		if(r >= DIJKSTRA::dis[i]) rans = (r - DIJKSTRA::dis[i]) / a[0] + 1;
		ans += rans - lans;
	}
	printf("%lld\n", ans);
	return 0;
}
posted @ 2020-08-29 20:14  Hock  阅读(168)  评论(0编辑  收藏  举报