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

题目链接:https://nanti.jisuanke.com/t/41299

题目:

题意:

给定a,b,m

a^{a^{a^{a^{...^{a}}}}} \%m(b个a)

解题历程:

提炼出式子之后直接快速幂暴力了,显然是不对的,幂次取过模了需要用到欧拉降幂

a^{b} \equiv \left\{\begin{matrix}a^{b\%\phi(p)},b<\phi(p) \\ a^{b\%\phi(p)+\phi(p)},b\geq \phi(p) \end{matrix}\right.   (mod p)

网络赛时打出锅了,网络赛后期脑子不清醒了,绕坑能力--,代码没存,赛后重打一次就过了,丝毫没有印象锅出在哪里555。

模板存住省得下次再踩坑。

题解:

1. O(n)线性筛预处理欧拉函数,phi[ 1 ] = 1

2. 对于欧拉降幂的dfs,坑点:

(1)如果不判断mod == 1,会多递归很多层直接tle

(2)注意flag和flag1的区分,两者不是同一个,flag是传给下一层的,flag1是上一层传过来,用于本层判断 b 和 phi[ p ] 的关系的

(3)mod == 1时flag = 1

3. 对于快速幂,坑点:

(1)判断中间所有乘的过程是否大于等于mod

(2)mi == 1跳出,因为这里的di不会再对ans有影响,大于等于mod也与结果无关,否则会wa

(3)循环外ans %= mod是为了填mi = 0,mod = 1时的坑

AC代码:

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

const int maxn = 1e6 +5;
int vis[maxn],prime[maxn],phi[maxn];

void init()
{
    int tot = 0;
    phi[1] = 1;
    for (int i = 2; i < maxn; i ++)
    {
        if (!vis[i])
        {
            prime[tot++] = i;
            phi[i] = i - 1;
        }
        vis[i] = 1;
        for (int j = 0; j < tot; j ++)
        {
            if(1ll * prime[j] * i >= maxn)break;
            vis[prime[j] * i] = 1;
            if (i % prime[j])
                phi[prime[j] * i] = phi[i] * (prime[j] - 1);
            else
            {
                phi[prime[j] * i] = phi[i] * prime[j];
                break;
            }
        }
    }
}

ll quickpow(ll di,ll mi,ll mod,int &flag)
{
    ll ans = 1;
    while(mi)
    {
        if(mi & 1)
        {
            ans = ans * di;
            if(ans >= mod)flag = 1;
            ans %= mod;
        }
        if(mi == 1)break;
        di = di * di;
        if(di >= mod)flag = 1;
        di %= mod;
        mi >>= 1;
    }
    if(ans >= mod)flag = 1;
    ans = ans % mod;
    return ans;
}

ll dfs(int a,int b,int mod,int &flag)
{
    int flag1 = 0;
    if(!b)
    {
        if (1 >= mod)flag = 1;
        return 1 % mod;
    }
    if(mod == 1)
    {
        flag = 1;
        return 0;
    }
    ll tmp = dfs(a,b - 1,phi[mod],flag1);
    if(flag1)
        return quickpow(a,tmp + phi[mod],mod,flag);
    return quickpow(a,tmp,mod,flag);
}


int main()
{
    int t;
    scanf("%d",&t);
    init();
    while(t --)
    {
        int a,b,mod;
        scanf("%d%d%d",&a,&b,&mod);
        int flag = 0;
        printf("%lld\n",dfs(a,b,mod,flag));
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值