同余最短路
这个东西是用来解决类似有 \(\sum_{i = 1}^n{a_ix_i} = V\) 类似这个限制下的一些最优化问题/判定的。但是这个东西的复杂度与 \(\min\{a_i\}\) 有关,所以什么二元不定方程组求解还是用 \(\rm exgcd\)。
problem: 给出 \(n\) 个整数 \(a_1, \dots, a_n\),求是否存在一组非负整数 \(x_1, \dots, x_n\),使得 \(\sum_{i = 1}^n{a_ix_i} = V\)。其中 \(\min\{a_i\} \le 5 \times 10^5, n \le 100, V \le 10^{18}\)。
首先不难发现假设可以通过一些组合达到 \(s\),那么显然 \(s + ka_1(k \ge 0)\) 显然都可以达到。那么现在相当于要求 \(v \equiv V \pmod {a_1}\) 的可以被组合出的 \(v \le V\)。于是那么这个东西相当于一个模 \(a_1\) 意义下的最短路。这个显然可以对于 \(0 \le i < a_1, 2 \le j \le n\),都连一条到 \((i + a_j) \bmod a_1\) 的边。跑最短路即可。时间复杂度为 \(O(nm\log nm)\)。当然也可以令 \(a\) 最大的为基准物品,这样就可以 \(\texttt{0-1bfs}\) 做到 \(O(nm)\)。
但这个不够优秀。我们需要一个不基于选择物品就可以做到 \(O(nm)\) 的算法。
不难发现一个大小为 \(x\) 的物品,会使得出现 \(\gcd(x, a_1)\) 个环(证明考虑起点位置),于是不妨对每个环单独考虑,那么着相当于一个完全背包,于是将整个环复制一遍,注意到显然不会绕着环走一圈,于是装两圈即可。这样每个点只被考虑了两遍,时间复杂度就是 \(O(nm)\) 的了。
qwq
#include<bits/stdc++.h>
#define ll long long
#define int long long
#define pir pair<int, int>
#define pb emplace_back
using namespace std;
const int N = 5e5 + 5, M = 20 + 5, INF = 1e18;
int n, l, r, a[M], f[N], mod = INF;
inline void chkmin(int& x, int y){if(y < x) x = y;}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin >> n >> l >> r;
for(int i = 1; i <= n; i++) cin >> a[i];
sort(a + 1, a + n + 1); int st = 1;
while(st <= n && (!a[st])) st++;
if(st == n + 1){cout << (l == 0); return 0;}
mod = a[st];
for(int i = 0; i < mod; i++) f[i] = INF;
f[0] = 0;
for(int i = st + 1; i <= n; i++){
for(int j = 0, lim = __gcd(a[i], mod); j < lim; j++){
for(int x = j, c = 0; c < 2; c += (x == j)){
int p = (x + a[i]) % mod;
chkmin(f[p], f[x] + a[i]); x = p;
}
}
}
int ans = 0;
for(int i = 0; i < mod; i++){
if(r >= f[i]) ans += (r - f[i]) / mod + 1;
if(l > f[i]) ans -= (l - 1 - f[i]) / mod + 1;
} cout << ans;
return 0;
}

浙公网安备 33010602011771号