模板 - 数论 - 扩展欧拉定理
欧拉定理:
$a^{\varphi(m)}=1\ mod\ m$ 当 $a,m$ 互质的时,
所以 $a^{c}=a^{c\ mod\ \varphi(m)}\ mod\ m$
可以用来化简幂次,比如求 $7^{222}\ mod\ 10$ 因为7和10互质,求出 $\varphi(10)=4$ 则 $7^4\ mod\ 10 =1$ ,提公因式 $7^{4*55+2}=1^{55}*7^2 =9=mod 10$
扩展欧拉定理:
推广到不互质的情况:
$a^{c}=a^{c\ mod\ \varphi(m)}$ 当 $gcd(a,m)=1$ 时
$a^{c}=a^{c}$ 当 $gcd(a,m)\neq1,c<\varphi(m)$ 时
$a^{c}=a^{c\ mod\ \varphi(m) + \varphi(m)}$ 当 $gcd(a,m)\neq1,c\geq\phi(m)$ 时
求欧拉函数:
筛法:
int phi[3000001]; void phi_table(){ //memset(phi,0,sizeof(phi)); phi[1]=1; for(int i=2;i<=3000000;i++){ if(!phi[i]) for(int j=i;j<=3000000;j+=i){ if(!phi[j]) phi[j]=j; phi[j]=phi[j]/i*(i-1); } } }
单个phi
ll phi(ll n) { ll ans = n; for(int i = 2; i*i <= n; i++) { if(n%i==0) { ans-=ans/i; while(n%i==0) n/=i; } } if(n > 1) ans-=ans/n; return ans; }
同时筛出质数表和欧拉函数表:
const int MAXN=10000000; bool check[MAXN+10]; int phi[MAXN+10]; int prime[MAXN+10]; int tot; void phi_and_prime_table(int N){ memset(check,0,sizeof(check)); phi[1]=1; tot=0; for(int i=2;i<=N;i++){ if(!check[i]){ prime[tot++]=i; phi[i]=i-1; } for(int j=0;j<tot;j++){ if(i*prime[j]>N) break; check[i*prime[j]]=1; if(i%prime[j]==0){ phi[i*prime[j]]=phi[i]*prime[j]; break; } else{ phi[i*prime[j]]=phi[i]*(prime[j]-1); } } } }
代码:使用扩展欧拉定理求大指数取模,注意减少c%phi(m)的次数,最后再取一次模(等于取不取都行)
注意用scanf忽略掉行末的换行符再getchar(这道题好像不可以fgets我猜他是没有'\n'结尾)
#include<bits/stdc++.h> using namespace std; #define ll long long ll p; //快速幂 x^n%p ll qpow(ll x,ll n) { ll res=1; while(n) { if(n&1) res=res*x%p; x=x*x%p; n>>=1; } return res%p; //要记得模p,否则输入一个2的幂次模1就挂了 } ll phi(ll n) { ll ans = n; for(int i = 2; i*i <= n; i++) { if(n%i==0) { ans-=ans/i; while(n%i==0) n/=i; } } if(n > 1) ans-=ans/n; return ans; } ll a,m,c; char sc[20000100]; int main() { scanf("%lld%lld ",&a,&m); ll phi_m=euler_phi(m); char sc=getchar(); while(isdigit(sc)){ c*=10; c+=(sc-'0'); if(c>=10000000){ c%=phi_m; c+=phi_m; } sc=getchar(); } p=m; if(c>phi_m){ c%=phi_m; c+=phi_m; } printf("%lld\n",qpow(a,c)); }