数论入门2——gcd,lcm,exGCD,欧拉定理,乘法逆元,(ex)CRT,(ex)BSGS,(ex)Lucas,原根,Miller-Rabin,Pollard-Rho
Posted ck6100lgev2
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数论入门2——gcd,lcm,exGCD,欧拉定理,乘法逆元,(ex)CRT,(ex)BSGS,(ex)Lucas,原根,Miller-Rabin,Pollard-Rho相关的知识,希望对你有一定的参考价值。
数论入门2
另一种类型的数论...
GCD,LCM
定义(gcd(a,b))为a和b的最大公约数,(lcm(a,b))为a和b的最小公倍数,则有:
将a和b分解质因数为(a=p1^{a1}p2^{a2}p3^{a3}...pn^{an},b=p1^{b1}p2^{b2}p3^{b3}...pn^{bn}),那么(gcd(a,b)=prod_{i=1}^{n}pi^{min(ai,bi)},lcm(a,b)=prod_{i=1}^{n}pi^{max(ai,bi)})(0和任何数的最大公约数是这个数,最小公倍数是0)
显然成立的吧。
所以我们有(gcd(a,b)*lcm(a,b)=ab)。
求(gcd(a,b))的方法:
首先我们有:(gcd(a,b)=gcd(b,a-b)(a>=b))
显然的啊,两个数相减怎么可能影响他们的最大公约数,毕竟是“公”约数,相减肯定还存在这个因子啊。
所以拓展一下我们就有:(gcd(a,b)=gcd(b,a \% b)(a>=b))
取模就是不断相减,所以也是成立的呀。
所以我们可以写出简洁的代码:
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
很显然这个复杂度是log的,每次至少减少一半。
lcm的话,(a/gcd(a,b)*b)即可。
然后呢,gcd和lcm具有交换律和结合律:
(gcd(a,b,c)=gcd(gcd(a,b),c)=gcd(c,b,a))
所以求多个数的gcd或lcm的时候就可以递推求啦。
还有一个东西就是(gcd(ka,kb)=k*gcd(a,b)),也是显然的。
exGCD
对于方程(ax+by=c),显然若(gcd(a,b)|c)的时候才有解。
因为不整除的话(ax+by)肯定有(c)不包含的因子,那样的话怎么可能有解呢?
然后呢,我们可以通过这样的方式快速借助求gcd的过程求出(ax+by=gcd(a,b))的一组解。
当(a=gcd(a,b),b=0)时,显然(x=1,y=0)。
令(a = b, b = a \% b),则有方程(b *x1 +(a \% b) * y1 = gcd(b, a \% b))
又因为(gcd(a, b) = gcd(b, a \% b)),且(a \% b = a - b * ?a / b?)
则(b * x1 + (a - b * ?a / b?) * y1 =gcd(a, b))
整理得:(a * y1 +b * (x1 - ?a / b? *y1) = gcd(a, b))
所以原方程中:(x = y1, y = x1 - ?a / b? *y1)。于是我们只要递归求出(x1, y1)就能求出(x, y)。
我们现在已经求得了(ax +by = gcd(a, b))的解,那么对于方程(ax + by = c (gcd(a, b) | c))呢?
因为已经知道(a *x1 +b * y1 = gcd(a, b))的解(x1, y1),左右两边同乘以(c / gcd(a, b)) 得:
(a * x1 * c / gcd(a, b) +b * y1 * c / gcd(a, b) = c)
则原方程的一组解(,x2 = x1 * c / gcd(a, b), y2 = y1 * c / gcd(a, b))
由此得出解集(,{(x, y) | x = x2 + k * b / gcd(a, b), y = y2 - k * a / gcd(a, b), k ∈ Z})
对于线性同余方程(axequiv cquad(modquad b)),我们怎么做呢?
显然可以转化成(ax+by=c)的形式,然后直接用扩欧解决啦。
贴个代码:
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b){x=1;y=0;return a;}
ll g=exgcd(b,a%b,y,x);y-=a/b*x;
return g;
}
欧拉定理
费马小定理:
若p是质数,且(gcd(a,p)=1),则(a^{p-1}equiv1(modquad p))。
欧拉定理:
若(gcd(a,p)=1),则(a^{varphi(p)}equiv1(nod quad p))。
扩展欧拉定理:
(a^bequiv egin{cases} a^{b\%varphi(p)}~~~~~~~~~~~gcd(a,p)=1\ a^b~~~~~~~~~~~~~~~~~~gcd(a,p) eq1,b<varphi(p)\ a^{b\%varphi(p)+varphi(p)}~~~~gcd(a,p) eq1,bgeqvarphi(p) end{cases}~~~~~~~(mod~p))
(varphi)为欧拉函数。
有个作用就是在算(a^b)的时候对b进行取模,使运算更高效,具体见luogu欧拉定理模板题
乘法逆元
若(gcd(a,b)=1,)(axequiv 1(mod~p)),则称x为a在模p意义下的乘法逆元。
那么求法就很显然了。
欧拉定理:a在模p意义下的逆元为(a^{varphi(p)-1})。
exGCD:当做一个同余方程求,但是要通过+kp的方式变为一个正数。
此外还有一个线性求逆元的算法。
首先,1在任何模数下的逆元都是1。
然后设(p=i*k+r,r<i,1<i<p)。
那么我们有(i*k+requiv 0(mod~p))
两边同时乘上(i^{-1}*r^{-1})得:
(k*r^{-1}+i^{-1}equiv 0(mod~p))
(i^{-1}equiv -k* r^{-1}(mod~p))
因为(k=lfloor p/i floor,r=p\%i),所以我们得到了逆元的递推式:
a[i]=-(p/i)*a[p%i]%p;
以及提一句,逆元是完全积性函数,从定义式里面就能看出来。
对于一个前缀积的序列的话,我们可以求出最后一项的逆元,然后(O(n))递推回去,实际上逆元可以理解为模意义下的(frac{1}{x}),怎么递推的话也很显然了,以阶乘为例:
fac[0]=1;
for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%P;
ifa[n]=ksm(fac[n],P-2);
for(int i=n-1;~i;i--) ifa[i]=ifa[i+1]*(i+1)%P;
还有就是:
((a/b)\%p=(a\%(bp))/ p)
证明:
((a/b)\%p=a/b-?(a/b)/p?*p)
(=a/b-?a/(b*p)?*p)
(=a/b-?a/(bp)?*b*p/b)
(=(a\%(bp) )/p)
CRT
已知系数全部为1的线性同余方程组:
(x equiv a_i(mod ~p_i)),其中(p_i)两两互质,求x的最小非负整数解。
那么我们考虑这样一个思路:
从1到n考虑每个同余方程组,我们设(M=prod_{i=1}^{n}p_i),那么当我们考虑到第i个方程的时候,我们设(T=frac{M}{p_i}),那么我们发现把第i个方程的解(x)加上(kT)的话,(x+kT)带到别的同余方程组的余数不会改变。
假设我们已经求出了前(i-1)个方程的通解(x),求出了第(i)个方程的一个解(x_i),那么显然,(Tx_i+x)是前(i)个方程的解。
我们用exGCD求出第i个线性同余方程组(Tx_iequiv a_i(mod~p_i))的解,一步步合并即可,因为(p_i)显然和(T)互质,所以实际上是求出逆元之后乘上(a_i)。
exCRT
已知系数全部为1的线性同余方程组:
(x equiv a_i(mod ~p_i)),其中(p_i)都是正整数,求x的最小非负整数解。
上面的算法失效了。为什么?都不一定互质了怎么可能还去求逆元?
所以我们要考虑一个新的思路:
假设我们已经求出了前(i-1)个方程的通解(x),设(M)为前i-1个数的lcm,那么我们发现(x+kM)如果能够满足第(i)个方程,那么前i个方程就都解出来啦。
我们写个式子:(x+kM equiv a_i(mod~p_i)),移项得(kM equiv a_i-x(mod ~p_i))。
那么我们解出来k之后,前i个方程的通解就出来啦,一步步做下去即可。
贴个代码:
ll mul(ll x,ll y,ll p){ll g=0;for(;y;y>>=1,x=(x+x)%p) if(y&1) g=(g+x)%p;return g;}
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b){x=1;y=0;return a;}
ll g=exgcd(b,a%b,y,x);y-=a/b*x;
return g;
}
for(int i=1;i<=n;i++) scanf("%lld%lld",&b[i],&a[i]);
ans=a[1];M=b[1];
for(int i=2;i<=n;i++)
{
ll A=M,B=b[i],c=(a[i]%B-ans%B+B)%B,x,y;
ll gcd=exgcd(A,B,x,y),d=B/gcd;
if(c%gcd) return 0;x=mul(x,c/gcd,d);
ans+=x*M;M*=d;ans=(ans%M+M)%M;
}
注意一下,因为是求lcm,所以那个B要除以gcd。
BSGS
exBSGS
原根
Lucas
exLucas
Miller-Rabin
Pollard-Rho
以上是关于数论入门2——gcd,lcm,exGCD,欧拉定理,乘法逆元,(ex)CRT,(ex)BSGS,(ex)Lucas,原根,Miller-Rabin,Pollard-Rho的主要内容,如果未能解决你的问题,请参考以下文章
hdu4497-GCD and LCM-(欧拉筛+唯一分解定理+组合数)