可恶的同余!

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;
}
posted @ 2021-10-22 15:45  keepcoder  阅读(47)  评论(0编辑  收藏  举报