可恶的同余!
ex(恶心)gcd
-
基本的:
求解同余方程:\(ax \equiv b \pmod{m}\)
那么这个方程等价于:\(ax-bm=b\)
稍微变换一下,有:\(ax+by=c\)
怎么求解?当 \(c=gcd(a,b)\) 时:
\[ax+by=(a,b) \]\[ax+by=(b,a\%b)=bx'+(a-\left\lfloor\frac{a}{b}\right\rfloor\times b)y' \]\[ax+by=ay'+b(x'-\left\lfloor\frac{a}{b}\right\rfloor \times y') \]所以得:$x=y' $, \(y=x'-\left\lfloor\frac{a}{b}\right\rfloor \times y'\)
代码:
ll xx,yy;
ll exgcd(ll a,ll b)
{
if(!b) {xx=1;yy=0;return a;}
ll d=exgcd(b,a%b);
ll t=xx;xx=yy;yy=t-a/b*yy;
return d;
}
- 一般的
上面求解的是一组特解,当 \(c\) 为任意数时,此方程的通解为:
\[\begin{cases}x=\dfrac{c}{d}x_{0}+k\dfrac{b}{d}\\y=\dfrac{c}{d}y_{0}+k\dfrac{a}{d}\end{cases}
\]
所以当求解 \(x\) 的最小整数解时让 \(x\) 模 \(\frac{b}{d}\) 即可。
exCRT(扩展中国剩余定理)
本质是合并方程。设前 \(i-1\) 个方程的通解为 \(ans_{i-1}\),前 \(i-1\) 个模数的 \(lcm\) 为 \(LCM\) ,有:
\[ans_{i}=ans_{i-1}+t\times LCM \tag{1}
\]
考虑要满足第 \(i\) 个方程: \(x\equiv a_{i} \pmod{m_{i}}\)
\[tLCM-km_{i}=a_{i}-ans_{i-1} \tag{2}
\]
用 \(exgcd\) 解出 \(t\) 的一组最小整数解,带回 \((1)\) 式求 \(ans_{i}\) 即可。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5;
ll xx,yy,m[N+5],a[N+5],n;
ll exgcd(ll a,ll b)
{
if(!b) {xx=1;yy=0;return a;}
ll d=exgcd(b,a%b);
ll t=xx;xx=yy;yy=t-a/b*yy;
return d;
}
ll mul(ll x,ll y,ll mod) {return (x*y-(ll)((long double)x/mod*y)*mod+mod)%mod;}
//O1快速乘
int main()
{
scanf("%lld",&n);
for(int i=1; i<=n; i++) scanf("%lld%lld",&m[i],&a[i]);
ll M=m[1],ans=a[1];
for(int i=2; i<=n; i++)
{
ll aa=M,b=m[i],c=(a[i]-ans%b+b)%b;
ll d=exgcd(aa,b);
if(c%d) return 0;
xx=mul(xx,c/d,b/d);
ans+=xx*M;
M*=b/d;//更新LCM
ans=(ans%M+M)%M;
//ans一定要在LCM内
}
printf("%lld\n",ans);
return 0;
}