学习:数学----欧拉定理与扩展欧拉定理
欧拉定理和扩展欧拉定理可以解决形如5100000000000000000000等大数幂取模或者求$a^x\ mod\ n=1$的大于1的最小x值等一类问题,其中欧拉函数占巨大的重要性,有效的将复杂的大数幂取模问题转化为简单的大数取模和快速幂问题,下面就来介绍一下基本的欧拉定理和扩展欧拉定理
欧拉函数的定义
欧拉函数$\varphi(n)$指$1$至$n$以内,与$n$互质的数的个数
当$n$比较小时,可以通过从前到后遍历的方法计算$\varphi(n)$
对于欧拉函数$\varphi(n)$,还有更简单的计算方法。
假如n可以通过分解质因子得到n的质因子$p_1,p_2,p_3,...,p_n$;
那么
$\varphi (n) = n(1-\frac{1}{p_1})(1-\frac{1}{p_2})(1-\frac{1}{p_3})...(1-\frac{1}{p_n})$
特别的,当$n=p^r$(p为质数)时(p是n的唯一质因子)
$\varphi (n) = p^r-count(p,2p,3p,...,p^r)$ (证明:由于$n$分解质因子只有p这一个质因子,故$n$以内与$n$不互质的数为p的倍数)
当$n=p_1^{r_1}p_2^{r_2}$时($p_1$和$p_2$是$n$的所有质因子)
含有$p1$的因子为$p_1,2*p_1,.....,p_2^{r_2}p_1^{r_1-1},p_2^{r_2}p_1^{r_1}$,一共$\frac{n}{p1}$个;
含有$p2$的因子为$p_2,2*p_2,.....,p_1^{r_1}p_2^{r_2-1},p_1^{r_1}p_2^{r_2}$,一共$\frac{n}{p2}$个;
既含有$p1$又含有$p_2$的因子为$p_1p_2,2p_1*p_2,3p_1*p_2.....p_1^{r_1-1}p_2^{r_2-1}$,一共$\frac{n}{p_1p_2}$个;
根据容斥定理可知与$n$不互质数的个数$k$为$\frac{n}{p_1}+\frac{n}{p_2}-\frac{n}{p_1p_2}$;
那么$\varphi(n)=n-k=n(1-\frac{1}{p_1})(1-\frac{1}{p_2})$;
因此可以推广到$n=p_1^{r_1}p_2^{r_2}....p_n^{r_n}$
1 ll getDivisor(){ 2 ll sum=p; 3 int i; 4 for(i=2;i*i<=p;i++){ 5 if(p%i==0) sum=(long long)sum*(1-1.0/i); 6 while(p%i==0) p=p/i; 7 } 8 if(p!=1) sum=(long long)sum*(1-1.0/p); 9 return sum;//sum为欧拉函数的值 10 }
欧拉函数的性质
1)当$n$为质数时 $\varphi(n)=n-1$
2)当$m$与$n$互质时 $\varphi(n)=\varphi(n)*\varphi(m)$
3)当$n$为质数时 $\varphi(2n)=\varphi(n)$
例如
$\varphi(6)=\varphi(3)=2$ 或$\varphi(6)=\varphi(3)*\varphi(2)=2*1=2$
欧拉定理
若$n$与$a$互质,则$a^{\varphi(n)}\equiv\ 1(mod\ n)$
首先来解释一下 $a^\varphi(n)\equiv\ 1(mod\ n)$ 是什么意思:
$a^{\varphi(n)}\equiv\ 1(mod\ n)$ 等价于 $a^{\varphi(n)}\ mod\ n==1\ mod\ n$
应用:可以解决$a^x\equiv\ 1(mod\ n)$或$a^x\ mod\ n=1\ mod\ n$的最小$x$的值的问题
由于最小$x$一定小于等于$\varphi(n)$,则令$\varphi(n)=t*x+b$,但由于我们算的$x$是最小的,故$b$等于$0$,可以得到$\varphi(n)$是$x$的倍数,因此只要遍历$\varphi(n)$的所有大于$log_an$因数,直到找到一个因数$k$使得$a^k\equiv\ 1(mod\ n)$成立,则$k$就是最小的$x$。
比如让你求$4^x\ mod\ 3=1$的最小$x$值:
$4$与$3$本身互质,最小$x$一定小于等于$\varphi(3)=2$,由于$2$的大于$log_43$的最小因数为$1$使得$4^x\ mod\ 3=1$成立,故$x$最小取$1$
特别的,当$n$是质数时,$a^x\equiv\ 1(mod\ n)$的最小$x$值为$n-1$
扩展欧拉定理
一个公式:$a_x\equiv a^{x\mod\varphi(n)+\varphi(n)}\mod n$ (n与x与a无需满足任何条件)
应用:运用扩展欧拉定理可以解决大数幂求模的问题,将利用大数求余很大的x转化为约等于Φ(n)的一个数,然后可以利用快速幂的方法得到结果!
如让你求$4^{9876543210213657854521}\mod 12345$的值:
可以通过分解质因子方法得到$\varphi(12345)=6576$,再利用大数求余求$9876543210213657854521\mod 6576=697$,再用快速幂求$4^{697+6576}\mod 12345=9319$(这个答案有问题,大家自己算算)
1 #include <iostream> 2 #include <algorithm> 3 #include <string> 4 #include <sstream> 5 #define ll1 (ll)1 6 using namespace std; 7 typedef long long ll; 8 stringstream stream; 9 ll p,divisor,pow1; 10 string str; 11 int t; 12 ll qSort(){ 13 ll x=4,sum=1; 14 while(pow1!=0){ 15 if(pow1%2!=0) sum=sum*x%p; 16 pow1=pow1>>1; 17 x=x*x%p; 18 } 19 return sum; 20 } 21 ll getPow(){ 22 stream<<str; 23 ll sum=0; 24 char c; 25 while(stream>>c) 26 sum=(10*sum+c-'0')%divisor; 27 stream.clear(); 28 return sum+divisor; 29 } 30 ll getDivisor(){ 31 ll sum=p; 32 int i; 33 ll p1=p; 34 for(i=2;i*i<=p1;i++){ 35 if(p1%i==0) sum=ll1*sum*(1-1.0/i); 36 while(p1%i==0) p1=p1/i; 37 } 38 if(p1!=1) sum=ll1*sum*(1-1.0/p1); 39 return sum; 40 } 41 int main(){ 42 cin>>t; 43 while(t--){ 44 cin>>str>>p; 45 divisor=getDivisor(); 46 pow1=getPow(); 47 cout<<qSort()%p<<endl; 48 } 49 return 0; 50 }
总结代码
扩展欧拉定理求an mod p代码:
#include <iostream> #include <string> #include <sstream> using namespace std; long long getOula_function(long long _mod){ long long i,sum=_mod; for(i=2;i*i<=_mod;i++){ if(!(_mod%i)) sum=(long long)sum*(1.0-1.0/i); while(!(_mod%i)) _mod/=i; } if(_mod!=1) sum=(long long)sum*(1.0-1.0/_mod); return sum; } long long getDivisor_function(string _str,long long _oula){ char c; long long sum=0; stringstream _stream; _stream<<_str; while(_stream>>c) sum=(10*sum+c-'0')%_oula; _stream.clear(); return sum; } long long qPow_function(long long _x,long long _divisor,long long _mod){ long long sum=1; while(_divisor){ if(_divisor&1) sum=sum*_x%_mod; _divisor=_divisor>>1; _x=_x*_x%_mod; } return sum; } long long pow_bigmod(long long _x,string _str,long long _mod){ long long _oula=getOula_function(_mod); long long _divisor=getDivisor_function(_str,_oula)+_oula; return qPow_function(_x,_divisor,_mod)%_mod; }
使用说明:首先放到代码里面,在main函数中输入pow_bigmod(long long a,string n,long long p),即可返回an mod p的值
欧拉定理求ax≡1(mod n)最小x代码:
#include <iostream> #include <cmath> using namespace std; long long getOula_function(long long _mod){ long long i,sum=_mod; for(i=2;i*i<=_mod;i++){ if(!(_mod%i)) sum=(long long)sum*(1.0-1.0/i); while(!(_mod%i)) _mod/=i; } if(_mod!=1) sum=(long long)sum*(1.0-1.0/_mod); return sum; } long long qPow_function(long long _x,long long _divisor,long long _mod){ long long sum=1; while(_divisor){ if(_divisor&1) sum=sum*_x%_mod; _divisor=_divisor>>1; _x=_x*_x%_mod; } return sum; } long long getMinDiv(long long _base,long long _mod){ long long _divisor=getOula_function(_mod); long long _flag=(long long)(log(_mod)/log(_base)); long long _top=(long long)sqrt(_divisor); for(long long i=_flag+1;i<=_top;i++) if(!(_divisor%i) && qPow_function(_base,i,_mod)==1) return i; for(long long i=_top;i>=1;i--) if(!(_divisor%i) && qPow_function(_base,_divisor/i,_mod)==1) return _divisor/i; }
使用说明:首先放到代码里面,在main函数中输入getMinDiv(long long base,long long mod),即可返回ax≡1(mod n)最小x的值。
ps:上面两个代码都包含了getOula_function(long long _mod)和qPow_function(long long _x,long long _divisor,long long _mod)函数!
例题
1.牛客练习赛44----D-小y的盒子:https://blog.csdn.net/weixin_43702895/article/details/89672825