快来踩爆这个蒟蒻吧|

Little_corn

园龄:1年1个月粉丝:11关注:17

2025-02-24 22:00阅读: 9评论: 0推荐: 0

同余最短路

这个东西是用来解决类似有 i=1naixi=V 类似这个限制下的一些最优化问题/判定的。但是这个东西的复杂度与 min{ai} 有关,所以什么二元不定方程组求解还是用 exgcd

problem: 给出 n 个整数 a1,,an,求是否存在一组非负整数 x1,,xn,使得 i=1naixi=V。其中 min{ai}5×105,n100,V1018

首先不难发现假设可以通过一些组合达到 s,那么显然 s+ka1(k0) 显然都可以达到。那么现在相当于要求 vV(moda1) 的可以被组合出的 vV。于是那么这个东西相当于一个模 a1 意义下的最短路。这个显然可以对于 0i<a1,2jn,都连一条到 (i+aj)moda1 的边。跑最短路即可。时间复杂度为 O(nmlognm)。当然也可以令 a 最大的为基准物品,这样就可以 0-1bfs 做到 O(nm)

但这个不够优秀。我们需要一个不基于选择物品就可以做到 O(nm) 的算法。

不难发现一个大小为 x 的物品,会使得出现 gcd(x,a1) 个环(证明考虑起点位置),于是不妨对每个环单独考虑,那么着相当于一个完全背包,于是将整个环复制一遍,注意到显然不会绕着环走一圈,于是装两圈即可。这样每个点只被考虑了两遍,时间复杂度就是 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;
}

本文作者:Little_corn

本文链接:https://www.cnblogs.com/little-corn/p/18735056

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Little_corn  阅读(9)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起