2019南京网络赛题目B super_log(欧拉降幂)

原题链接

题目要求算出幂塔函数 a^ ( a ^ ( a ^ (…)))共 b 个 a 乘幂的结果模m的值。由于指数会非常大,使用欧拉定理递归降幂。

但是不能直接使用,欧拉降幂有三种方式(在不同条件下)

所以需要每次判断a与目前模数p是否互质,以及判断指数b与目前的模数之前的大小关系,来判断每次使用哪种方式递归降幂。



AC代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#pragma GCC optimize(3)  //2
using namespace std;
typedef long long ll;
ll get_phi(ll n)
{
    ll res=n;
    for(int i=2;i<=n/i;i++)
    {
        if(n%i==0)
        {
            res=res/i*(i-1);
            while(n%i==0) n/=i;
        }
    }
    if(n>1)
        res=res/n*(n-1);
    return res;
}
ll q_pow(ll a,ll b,ll p)
{
	ll ans=1;
	while(b)
	{
		if(b&1)
			ans=ans*a%p;
		a=a*a%p;
		b>>=1;
	 } 
	 return ans;
}
ll f(ll a,ll cnt,ll p)
{
	if(cnt==0||p==1)
		return 1;
	ll phi=get_phi(p);
	ll b=f(a,cnt-1,phi);
	if(__gcd(a,p)==1)    //第一种
		return q_pow(a,b%phi,p);
	else if(b&&b<phi)    //第二种(注意b为0的时候不能用第二种!)
		return q_pow(a,b,p);
	else                 //第三种
		return q_pow(a,b%phi+phi,p);
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		ll a,b,p;
		scanf("%lld%lld%lld",&a,&b,&p);
		printf("%lld\n",f(a,b,p)%p);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值