拓欧&中国剩余定理
拓欧
求 \(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
函数可以用龟速乘实现,是为了防止溢出。