大数翻倍法求解中国剩余定理

考虑用一种暴力的方法将其合并成一个同余方程。让我们设初始的 x=0,m=1,合并了第一个方程后变为 x=a1,m=m1。

那么现在只需要满足第二个同余方程即可。我们知道 (a1+km1)modm1=a1,一个显然的想法是每次暴力的加 m1,然后暴力的判断能否满足第二个同余方程。找到一个能满足的情况合并即可,模数合并为 lcm(m1,m2),代码也十分好写,只有四行:

void Merge(LL &a1, LL &m1, LL a2, LL m2) {
while(a1 % m2 != a2) a1 += m1;
m1 = Lcm(m1, m2);
}
复杂度证明
设满足情况时加了 k 次 m1,那么有:

a1+km1≡a2(modm2)
假设 k=m2,即加了 m2 次,那么:

a1+m2m1≡a1(modm2)
所以说加 k 次所得到的模数的循环节的大小为 m2。

所以上面代码每次合并的复杂度是 O(m2) 的。

如果一次枚举超过了 m2 次还没有得到答案,那么我们可以判定这组同余方程无解,因为在循环下去也还是那些余数,没有什么意义了。

判断无解情况的代码(就是加了个枚举的限制而已

发现更小的模数的复杂度更优,所以我们添一句优化,通过特判转换一下枚举的模数即可。代码改为:

void Merge(LL &a1, LL &m1, LL a2, LL m2) {
if(m1 < m2) swap(m1, m2), swap(a1, a2);
while(a1 % m2 != a2) a1 += m1;
m1 = Lcm(m1, m2);
}
所以总的复杂度为 O(∑ni=1mi)。

但是!它的复杂度真的有那么高吗?(那我也没必要写这篇博客了是吧

我们知道答案一定在 long long 范围内,并且 ∏ni=1mi 一定也不会爆 long long。

因为高精度求解同余方程组也没那个做法是吧,出题人也一定不会出个爆 long long 的样例,因为他自己也做不了。

让我们来考虑最坏情况:

想要卡我们,每个模数都得是一个大质数。还要保证成绩和在 long long 范围内(也就是 1018)。

那么只有一种情况, n=2!此时 mi 可以做到 2×109 级别的大质数。总时间复杂度为 O(109) ,可以被卡。

但是,当 n=3 时, mi 只有 106 级别,我们的复杂度也只有 O(3×106) ,可以通过。

n 更大的情况就不必说了吧。

大数翻倍法的优势
码量小
理解难度小
一般不会被卡,没有人会对着这个非主流算法卡十个点的
不需要考虑模数互质的情况
最后的最后:上代码!
/*
Work by: Suzt_ilymics
Problem: 不知名屑题
Knowledge: 大数翻倍法
Time: O(能过)
*/
#include
#include
#include
#include
#include
#define LL long long
#define orz cout<<“lkp AK IOI!”<<endl
using namespace std;
LL n, v, d, a, b;
LL read(){
LL s = 0, f = 0;
char ch = getchar();
while(!isdigit(ch)) f |= (ch == ‘-’), ch = getchar();
while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - ‘0’ , ch = getchar();
return f ? -s : s;
}

LL Gcd(LL x, LL y) { return !y ? x : Gcd(y, x % y); }
LL Lcm(LL x, LL y) { return x / Gcd(x, y) * y; }
void Merge(LL &a1, LL &m1, LL a2, LL m2) {
if(m1 < m2) swap(m1, m2), swap(a1, a2);
while(a1 % m2 != a2) a1 += m1;
m1 = Lcm(m1, m2);
}

int main()
{
n = read(); v = 0, d = 1; // 初始化
for(int i = 1; i <= n; ++i) a = read(), b = read(), b %= a, Merge(v, d, b, a);
printf("%lld", v);
return 0;
}
如果觉得写的不错就点个赞吧这个做法顶上去吧/kel
USB Microphone https://www.soft-voice.com/
Wooden Speakers https://www.zeshuiplatform.com/
亚马逊测评 www.yisuping.cn
深圳网站建设www.sz886.com

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值