降冪公式:
模板題:
Exponial .
計算:exponial(n)%m . (1<= n,m <= 109)
exponial(n) = n^ (n-1^ ( n-2^ ( n-3^ (n-4^ (…^ 1))))
詳情看代碼註釋
#include<bits/stdc++.h>
using namespace std;
#define inf (long long)0x3f3f3f3f
long long tmp;
long long euler(long long n)//求一個數的歐拉函數
{
long long ans=n;
for(long long 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;
}
long long pow2(long long a,long long n)//tmp的快速冪
{
long long ans = 1;
while(n)
{
if(n&1)
ans = min(inf,ans*a);
a = min(a*a,inf);
n>>=1;
}
return ans;
}
long long qui_pow(long long a,long long n,long long mod)//普通快速冪
{
long long ans =1;
while(n)
{
if(n&1)
ans = ans*a%mod;
a = a*a%mod;
n>>=1;
}
return ans;
}
//降冪公式
//A^B mod(C) = A^(B mod euler(C)) mod C when (B < euler(C))
//A^B mod(C) = A^(B mod euler(C)+euler(C)) mod C when (B >= euler(C))
long long dfs(long long n,long long mod)//每次的模數爲上一次的歐拉函數,所以最多調用log(n)次遞歸函數,
{
if(mod==1||n==1)//本次遞歸的模數是1或者遞歸到n=1,可以得到結果
{
tmp = 1;
return 1%mod;//當mod==1時返回結果一定是0,因爲任何數模1都是0; 當n==1時,返回結果是1%mod
}
long long ans;
long long exp = dfs(n-1,euler(mod));//冪層遞歸的模數是本層模數的歐拉函數
if(tmp>=euler(mod))
ans = qui_pow(n,exp+euler(mod),mod)%mod;//這裏和下面exp沒有像公式裏的模euler(mod),是因爲 (上一層的mod)==(這一層的euler(mod)),已經在上一層模完了
else
ans = qui_pow(n,exp,mod)%mod;
tmp = min(inf,pow2(n,tmp));//tmp是記錄的真實的,不被模的冪,以此判斷使用哪個降冪公式,取一個比最大的模數大的數inf作爲tmp的最大值,以免乘爆
return ans;
}
int main()
{
long long num;
cin>>num;
print(num);
long long i,j,m,n,mod;
ios::sync_with_stdio(false);
while(scanf("%lld %lld",&n,&mod)!=EOF)
{
cout<<dfs(n,mod)<<endl;
}
return 0;
}