DestinHistoire

 

BZOJ-3884 上帝与集合的正确用法(欧拉降幂)

题目描述

  求:

\[2^{2^{2^{2\cdots}}} \]

  无限个 \(2\)\(p\) 取模后的值。

  数据范围:\(T\leq 1000,p\leq 10^7\)

分析

  根据扩展欧拉定理,当 \(b\geq \varphi(p)\) 时:

\[a^b\equiv a^{b\mod{\varphi(p)+\varphi(p)}}\pmod{p} \]

  指数变成了和原问题同样的形式,可以递归处理。

  可以发现除了第一次之外,模数都是偶数,所以每次递归模数都会至少除以 \(2\)。因此在不超过 \(O(\log p)\) 次递归之后,模数就会变成 \(1\),此时递归结束,回溯并计算结果即可。

  如果用线性筛计算欧拉函数,时间复杂度为 \(O(p+T\log_2 p)\);如果每次 \(O(\sqrt{p})\) 计算欧拉函数,时间复杂度 \(O(T\log_2 p\sqrt{p})\),显然选择后者。

代码

#include<bits/stdc++.h>
using namespace std;
long long quick_pow(long long a,long long b,long long p)
{
    long long ans=1;
    while(b)
    {
        if(b&1)
            ans=ans*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ans;
}
long long phi(long long n)
{
    long long ans=n;
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            ans=ans/i*(i-1);
            while(n%i==0)
                n=n/i;
        }
    }
    if(n>1)
        ans=ans/n*(n-1);
    return ans;
}
long long solve(long long p)
{
    if(p==1)
        return 0;
    return quick_pow(2,solve(phi(p))+phi(p),p);
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        long long p;
        scanf("%lld",&p);
        printf("%lld\n",solve(p));
    }
    return 0;
}

posted on 2020-11-11 18:18  DestinHistoire  阅读(100)  评论(0)    收藏  举报

导航