Exponial Kattis - exponial(歐拉降冪)

降冪公式:
在這裏插入圖片描述
模板題:
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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章