同余最短路的转圈法
学习自 Alex_Wei 的博客。
同余最短路模板题:[国家集训队] 墨墨的等式。
已知长为
的序列 。对于不定方程 ,问有多少 可以使得方程有解。
, , 。
本文默认取模得到的结果都是自然数。
首先把询问拆成区间
设集合
设集合
我们随便选一个
显然
考虑如何求
一种方法是建图,用最短路解决。点数为
但是还有另一种方式,考虑逐个添加
(箭头表示“更新”)
对于每个
由于模数相同时,不同的剩余类交集为空,所以考虑对于每个剩余类中的下标分别更新。形式化地说,就是对每个
for(int p = i, c = 0; c < 2; c += p == i) {
gmin(f[(p + a[j]) % a[1]], f[p] + a[j]);
p = (p + a[j]) % a[1];
}
每次可以更新
时间复杂度
#include<bits/stdc++.h>
#define endl '\n'
#define rep(i, s, e) for(int i = s, i##E = e; i <= i##E; ++i)
#define int long long
#define gmin(x, y) (x = min(x, y))
using namespace std;
constexpr int N = 15, A = 5e5;
int n, a[N], l, r, f[A];
signed main() {
#ifdef ONLINE_JUDGE
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
#endif
cin >> n >> l >> r;
rep(i, 1, n) cin >> a[i];
sort(a + 1, a + n + 1);
memset(f, 0x3f, sizeof f);
f[0] = 0;
rep(j, 2, n) rep(i, 0, __gcd(a[1], a[j]) - 1)
for(int p = i, c = 0; c < 2; c += p == i) {
gmin(f[(p + a[j]) % a[1]], f[p] + a[j]);
p = (p + a[j]) % a[1];
}
int ans = 0;
--l;
rep(i, 0, a[1] - 1) {
if(l >= f[i]) ans -= (l - f[i]) / a[1] + 1;
if(r >= f[i]) ans += (r - f[i]) / a[1] + 1;
}
cout << ans << endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?