「学习笔记」同余最短路

同余最短路,可以用来解决像“给定 n 个整数,求这 n 个整数能拼凑出多少的其他整数(n 个整数可以重复取),以及给定 n 个整数,求这 n 个整数不能拼凑出的最小(最大)的整数,或者至少要拼几次才能拼出模 Kp 的数”的问题。
同于最短路是利用同余来构造状态,状态转移通常为 fi+j=fi+j,类似于 disv=disu+eu,v


n 个数,分别为 a1,a2,a3,a4,,an ,算出这 n 个数最大的不能拼出的数,50n107

某凯的疑惑?
只能说很像,但不完全是,毕竟这有 n 个数,某凯的疑惑是两个数。
这里,我们就可以用同余最短路来做了,首先,取出 min1n(ai) 来作为我们的模数 mod,对于一个余数 x(0xmod1),会有一个数 k,使得 kmod+x 可以被拼出而 k(mod1)+x 不能被拼出,那么,对于 x 来说,k(mod1)+x 就是最大的不能被拼出的数,对于每一个余数,我们会发现,都有一个 k 可以满足这样的关系(k 可能为负数),因此我们只需要找出这些数中最大的数即可。具体如何操作,看代码。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, int> pil;
#define fir first
#define sec second

const int N = 1e7 + 5;

int n, m, seed, mod;
int a[N];
ll dis[N];
bool vis[N];

void dijkstra() {
	priority_queue<pil, vector<pil>, greater<pil>> q;
	for (int i = 0; i <= mod; ++ i) {
		dis[i] = 1e18;
	}
	q.push({0, 0});
	dis[0] = 0;
	while (!q.empty()) {
		pil it = q.top();
		q.pop();
		int u = it.second;
		if (dis[u] != it.first)	continue;
		for (int i = 1; i <= n; ++ i) {
			int v = (u + a[i]) % mod;
			if (dis[v] > dis[u] + a[i]) {
				dis[v] = dis[u] + a[i]; // 找到最小的能被拼出的数
				q.push({dis[v], v});
			}
		}
	}
}

int main() {
	scanf("%d%d%d", &n, &m, &seed);
	mt19937 rng(seed);
	auto get = [&]() {
		uniform_int_distribution<int> qwq(2, m);
		return qwq(rng);
	};
	mod = m;
	for (int i = 1; i <= n; i++) {
		a[i] = get();
		mod = min(mod, a[i]);
	}
	dijkstra();
	ll ans = -1;
	for (int i = 0; i < mod; ++ i) {
		ans = max(ans, dis[i] - mod);
		// dis 中存的是最小的能被拼出的数
		//所以只要再 -mod,就是最大的不能拼出的数
	}
	printf("%lld\n", ans);
	return 0;
}

作者:yifan0305

出处:https://www.cnblogs.com/yifan0305/p/17299790.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

转载时还请标明出处哟!

posted @   yi_fan0305  阅读(76)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
more_horiz
keyboard_arrow_up light_mode palette
选择主题
点击右上角即可分享
微信分享提示