2019 icpc南京網絡賽 B super_log(歐拉降冪)

鏈接


題意:

在這裏插入圖片描述
求最小的x,滿足log*(x)>=b


思路:

容易發現答案就是 aaa...a^{a^{a^{...}}}
首先不要犯一個錯誤: aaa!=(aa)aa^{a^{a}} !=(a^{a})^{a}  (aa)a=aaa(a^{a})^{a}=a^{a*a}
歐拉函數有:
在這裏插入圖片描述
如果原數爲AAC,CAB=ACA^{A^C},C爲A的省略,記B=A^C,那麼解決B就是解決原數的一個子問題,那麼可以利用遞歸來解決這個問題。
遞歸的終點顯然是深度爲B,但是這樣會超時,繼續觀察一下,發現在遞歸的時候,模數差不多是歐拉函數套歐拉函數,最後模數很快就會變成1,然後在遞歸下去全部模1變爲0就沒有意義在遞歸下去了,就需要及時返回。



參考代碼:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn =1e6+5;
bool vis[maxn];
ll phi[maxn];
ll p[maxn];
void work_euler(int n)//On
{
    memset(vis,1,sizeof(vis));
    vis[0]=vis[1]=false;
    phi[1]=1;
    for (int i=2;i<=n;i++)
    {
        if(vis[i]) p[++p[0]]=i,phi[i]=i-1;
        for(int j=1;j<=p[0]&&p[j]*i<=n;j++)
        {
            vis[p[j]*i]=false;
            if (i%p[j]) phi[p[j]*i]=phi[p[j]]*phi[i];
            else{phi[p[j]*i]=p[j]*phi[i];break;}
        }
    }
}

ll q_pow(ll a,ll n,ll m){
    ll res=1;
    while(n){
        if(n&1)res=res*a%m;
        a=a*a%m;
        n>>=1;
    }
    return res;
}
ll a,b;
ll solve(ll k,ll m){
    if(k>b||m==1)return 1;
    ll zs=solve(k+1,phi[m]);
    double cmp=log(m)/log(a);//換底公式loga(m)
    if(zs-cmp>=0)return q_pow(a,zs,m)+m;
    else return q_pow(a,zs,m);
}
int main(){
    work_euler(maxn-5);
    int T;
    scanf("%d",&T);
    while(T--){
        ll m;
        scanf("%lld%lld%lld",&a,&b,&m);
        ll ans=1;
        if(b==0)printf("%lld\n",ans%m);//簡單情況直接特判
        else if(b==1)printf("%lld\n",a%m);
        else if(b==2)printf("%lld\n",q_pow(a,a,m));
        else printf("%lld\n",solve(1,m)%m);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章