拓欧&中国剩余定理

拓欧

\(ax+by=\gcd(a,b)\)
要想求 \(ax+by=\gcd(a,b)\)
先求 \(bx'+(a \mod b)y'=\gcd(b,a \mod b)=\gcd(a,b)\)
\(bx'+(a-(a/b)\times b)y'=ax+by\)
\(bx'+ay'-((a/b)\times b)y'=ax+by\)
\(ax+by=ay'+b(x'-(a/b)y')\)
\(x=y'\)
\(y=x'-(a/b)y'\)

#include<algorithm>
#include<cstdio>
#include<iostream>
using namespace std;
int a,b,x,y;
int exgcd(int a,int b,int &x,int &y) {
	if(b==0) {x=1; y=0; return a;}	
	int g=exgcd(b,a%b,x,y);
	int z=x;
	x=y; y=z-(a/b)*y;
	return g;
}
int main() {
	scanf("%d %d",&a,&b);
	exgcd(a,b,x,y);
	printf("%d %d\n",x,y);
	return 0;
}

现在已经求出了一组特解 \(x_0,y_0\) ,通解为:
\(x=x_0+kb\)
\(y=y_0+ka (k\in Z)\)

乘法逆元

拓欧解法:
\(x\) 的逆元即为 \(x^{-1}\),满足 \(x\times x^{-1}\equiv 1 \pmod p\)
\(a=x^{-1}\),
\(ax\equiv 1 \pmod p\).
则求 \(ax+kp=1\).
用拓展欧几里得定理可以完成.
注意要求 \(a\) 的最小正整数解即为 \(a \bmod p\).

递推做法:

中国剩余定理(孙子定理)

求解 \(\begin{cases}x\equiv a_1 \pmod {m_1}\\x\equiv a_2 \pmod {m_2}\\x\equiv a_n \pmod {m_n}\end{cases}\)

\(M=\prod m_i\)\(M_i=\dfrac{M}{m_i}\).
求出 \(M_i\) 关于 \(m_i\) 的逆元 \(t_i\),即 \(M_it_i \equiv 1\pmod {m_i}\).

\(x=\sum (a_iM_it_i) + kM (k\in Z)\).

证明:
\(a_iM_it_i\equiv a_i \pmod {m_i}\),同时
\(a_jM_jt_j\equiv 0 \pmod {m_i}(i\not=j)\),因为 \(m_i|M_j\)
所以 \(\sum (a_iM_it_i)\equiv a_i \pmod {m_i}\)
\(x\) 满足所有方程的解

P3868 [TJOI2009] 猜数字

#include<algorithm>
#include<cstdio>
#include<iostream>
using namespace std;
const int N=20;
typedef long long ll;
ll n,a[N],b[N],mul=1,m[N],t[N],ans;
ll exgcd(ll a,ll b,ll &x,ll &y) {
	if(b==0) {x=1; y=0; return a;}
	ll g=exgcd(b,a%b,x,y);
	ll z=x; x=y; y=z-(a/b)*y;
	return g;
}
ll calc(ll p,ll q,ll mod) {
	return (p*(q/10)%mod*10%mod+p*(q%10)%mod)%mod;
}
int main() {
	scanf("%lld",&n);
	for(int i=1; i<=n; i++)
		scanf("%lld",&a[i]);
	for(int i=1; i<=n; i++) {
		scanf("%lld",&b[i]); //x mod b[i]=a[i]
		mul*=b[i];
	}
	for(int i=1; i<=n; i++)	{
		m[i]=mul/b[i]; // m[i]t[i] mod b[i]=1 
		ll x,k; //m[i] x+ b[i]k = 1
		exgcd(m[i],b[i],x,k);
		x=(x%b[i]+b[i])%b[i];
		t[i]=x;
	}
	for(int i=1; i<=n; i++)
		ans=(ans+calc(a[i],calc(m[i],t[i],mul),mul))%mul;
	printf("%lld\n",ans);
	return 0;
}

这里的 calc 函数可以用龟速乘实现,是为了防止溢出。

posted @ 2022-08-13 13:36  s1monG  阅读(21)  评论(0编辑  收藏  举报