[欧拉降幂][2019南京网络赛B]super_log

题意:输入a,b,p,求(底数a的右上角有b-1个a)

思路: 

广义欧拉定理:

AC代码:

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;

ll a,b,m;
ll vis[1000005];
ll prime[1000005],num=0;
ll phi[1000005];

void getphi(ll n=1000000){
    phi[1]=1;
    for(ll i=2;i<=n;i++){
        if(!vis[i]) prime[++num]=i,phi[i]=i-1;
        for(ll j=1;j<=num;j++){
            ll k=i*prime[j];
            if(k>n)break;
            vis[k]=1;
            if(i%prime[j]==0){
                phi[k]=phi[i]*prime[j];
                break;
            }
            phi[k]=phi[i]*(prime[j]-1);
        }
    }
    return;
}

ll qpow(ll a,ll b,ll mod){
  ll ret=1;
  while(b){
    if(b&1) ret=ret*a%mod;
    a=a*a%mod;
    b>>=1;
  }
  return ret;
}

ll check(ll d,ll cmp){
  ll res=a;
  for(ll i=1;i<=d;i++){
    ll tmp=1;
    for(ll j=1;j<=res;j++){
        tmp=tmp*a;
        if(tmp>=cmp) return 1;
    }
    res=tmp;
  }
  return -1;
}

ll fun(ll d){
  ll res=a;
  for(ll i=1;i<=d;i++){
    ll tmp=1;
    for(ll j=1;j<=res;j++) tmp=tmp*a;
    res=tmp;
  }
  return res;
}

ll cal(ll d,ll p){
  if(p==1) return 0;

  if(d==0) return a%p;

  ll tmp;
  if(__gcd(a,p)==1) tmp=cal(d-1,phi[p]);//gcd(a,p)==1
  else{
      if(check(d-1,phi[p])<0) tmp=fun(d-1);//gcd(a,p)!=1&&b<phi(p)
      else tmp=cal(d-1,phi[p])+phi[p];//gcd(a,p)!=1&&b>=phi(p)
  }
  ll ret=qpow(a,tmp,p);
  return ret;
}

int main()
{
    getphi();
    ll t;scanf("%lld",&t);
    while(t--){
        scanf("%lld%lld%lld",&a,&b,&m);
        if(a==1||b==0){
            printf("%lld
",1%m);
            continue;
        }
        ll ans=cal(b-1,m);
        printf("%lld
",ans%m);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/lllxq/p/11444011.html