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) 收藏 举报
浙公网安备 33010602011771号