題意
求冪塔函數,b個a mod m .
擴展歐拉定理
理解:這兩種情況必須要分,但是特例很少,所以很多代碼沒有考慮到第二種情況(B>=phi(C))但是仍然可以過,應該是數據水,沒有特例的情況,也可能不會出現特例??
比如 6^1 % 2560 = 6 , 6^ (1+phi(2560)) %2560 => 6^1025 = 4096 ,2560的歐拉值是1024,小於1025,所以這就是第二種情況的一個特例。但是很多其他的都符合,不過考慮加上phi(C). 用指數循環節理解:在開頭一部分,比較特殊,在之後纔有循環,但是開頭的這個並不一定是按照循環來的,所以開頭的和後面循環的不一定相等(但是大多數情況都是相等的,只有少數特例),所以纔有上述公式的兩種情況,表示循環節前的和循環節。
求歐拉函數模板
打表,用於處理多個數據,數據範圍最大大概爲5億(一維數組大小)
ll phi[N],prime[N];
ll tot;
void init(){
phi[1]=1;
for(ll i=2;i<N;i++){
if(!phi[i]){
phi[i]=i-1;
prime[tot++]=i;
}
for(ll j=0;j<tot && i*prime[j]<N;j++){
if(i%prime[j]) phi[i*prime[j]] = phi[i]*(prime[j]-1);
else{
phi[i*prime[j]] = phi[i]*prime[j];
break;
}
}
}
}
單次計算,如果多次計算,每次都要重複計算,但是可以處理很大到long long 的數據
ll phi(ll n)
{
ll k = (ll)sqrt(n+0.5);
ll ans = n;
for(int i=2;i<=k;i++) {
if(n%i==0){
ans = ans/i*(i-1);
while(n%i==0) n /= i;
}
}
if(n>1) ans = ans/n*(n - 1);
return ans;
}
歐拉降冪
有一種黑科技可以不用考慮B和phi(C)的比較 ,用一個自定義的MOD函數可以迴避這種比較討論,黑科技證明
ll MOD(ll x,ll m)
{
return x>m?x%m+m:x;
}
ll Pow(ll x,ll y,ll m)
{
ll ans=1;
while(y){
if(y&1) ans = MOD(ans*x,m);
x = MOD(x*x,m);
y >>= 1;
}
return ans;
}
用了自定義的MOD之後,需要注意的是當取模的數p,if(p==1)return a; 不是返回0。有很多其他的降冪都是寫的返回0,但是在其他的地方分類比較了,但感覺更多的是因爲數據水?歐拉定理對不互質的兩種情況的公式,很多博客的代碼都是迴避的,也就是直接用快速冪,沒有考慮取模的是大於phi還是小於phi,但是都能AC.
#include <bits/stdc++.h>
using namespace std;
#define N 1000010
typedef long long ll;
ll phi[N],prime[N];
ll tot;
void init(){
phi[1]=1;
for(ll i=2;i<N;i++){
if(!phi[i]){
phi[i]=i-1;
prime[tot++]=i;
}
for(ll j=0;j<tot && i*prime[j]<N;j++){
if(i%prime[j]) phi[i*prime[j]] = phi[i]*(prime[j]-1);
else{
phi[i*prime[j]] = phi[i]*prime[j];
break;
}
}
}
}
ll MOD(ll x,ll m)
{
return x>m ? x%m+m : x;
}
ll Pow(ll x,ll y,ll m)
{
ll ans=1;
while(y){
if(y&1) ans = MOD(ans*x,m);
x = MOD(x*x,m);
y >>= 1;
}
return ans;
}
ll solve(ll a,ll b,ll p){
if(p==1)return a;
if(b==0)return 1;
ll P=solve(a,b-1,phi[p]);
return Pow(a,P,p);
}
int main()
{
init();
int t;scanf("%d",&t);
while(t--){
ll a,b,mod;
scanf("%lld%lld%lld",&a,&b,&mod);
ll ans = solve(a,b,mod);
printf("%lld\n",ans%mod);
}
return 0;
}