P2371 [国家集训队] 墨墨的等式

Sol

同余最短路板子。

考虑拎出一个数 \(x\),记 \(d_i\) 为除了 \(x\) 外的数跑背包选的数模上 \(x\) 的最小数,那么对于模 \(x\) 等于 \(i\) 的所有能凑出来的数和 \(d_i,d_i+x,d_i+2x,\dots\) 一定等价。

于是做完了。

Code

#include <bits/stdc++.h>
#define x first
#define y second
#define pb push_back
#define eb emplace_back
#define pf push_front
#define desktop "C:\\Users\\MPC\\Desktop\\"
#define IOS ios :: sync_with_stdio (false),cin.tie (0),cout.tie (0)
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair <int,int> PII;
const int dx[] = {1,0,-1,0},dy[] = {0,-1,0,1};
template <typename T1,typename T2> bool tomax (T1 &x,T2 y) {
	if (y > x) return x = y,true;
	return false;
}
template <typename T1,typename T2> bool tomin (T1 &x,T2 y) {
	if (y < x) return x = y,true;
	return false;
}
LL power (LL a,LL b,LL p) {
	LL ans = 1;
	while (b) {
		if (b & 1) ans = ans * a % p;
		a = a * a % p;
		b >>= 1;
	}
	return ans;
}
int fastio = (IOS,0);
#define endl '\n'
#define puts(s) cout << (s) << endl
const int N = 20,M = 500010;
int n,m;
LL l,r;
int a[N];
vector <PII> g[M];
LL dist[M];
bool st[M];
void SPFA (int s) {
	memset (dist,0x3f,sizeof (dist));
	dist[s] = 0;
	queue <int> q;
	q.push (s);
	while (q.size ()) {
		int u = q.front ();
		q.pop ();
		st[u] = 0;
		for (auto [v,w] : g[u]) {
			if (dist[v] > dist[u] + w) {
				dist[v] = dist[u] + w;
				if (!st[v]) {
					q.push (v);
					st[v] = 1;
				}
			}
		}
	}
}
LL query (LL x) {
	LL ans = 0;
	for (int i = 0;i < m;i++) {
		if (dist[i] <= x) ans += (x - dist[i]) / m + 1;
	}
	return ans;
}
void mian () {
	cin >> n >> l >> r;
	m = 1e9;
	for (int i = 1;i <= n;i++) {
		cin >> a[i];
		if (a[i]) tomin (m,a[i]);
	}
	for (int i = 0;i < m;i++) {
		for (int j = 1;j <= n;j++) {
			if (a[j] && a[j] != m) g[i].pb ({(i + a[j]) % m,a[j]});
		}
	}
	SPFA (0);
	cout << query (r) - query (l - 1) << endl;
}
int main () {
	int T = 1;
	// cin >> T;
	while (T--) mian ();
	return 0;
}
posted @ 2025-05-17 19:25  incra  阅读(11)  评论(0)    收藏  举报