题意简述
求 2 2 2 2 2 2 . . . 2 2^{2^{2^{2^{2^{2^{^{{...}^{2}}}}}}}} 222222...2的值(其中有无穷个2)对 p ( p < = 1 e 7 ) p(p<=1e7) p(p<=1e7)取余数。多组数据。
数据
输入
第一行一个 T T T,表示数据个数。接下来 T T T行,每行一个 p p p。
输出
对于每个数据,给出答案。
样例
输入
3
2
3
6
输出
0
1
4
思路
正无穷个 2 2 2叠在一起诶。。。这个怎么算啊。。。
别急,我们不是还有欧拉定理呢么。我们会发现,在降幂时,我们将指数膜 ϕ ( p ) \phi(p) ϕ(p),然后膜 ϕ ϕ ( p ) \phi\phi(p) ϕϕ(p),然后膜 ϕ ϕ ϕ ( p ) ⋯ \phi\phi\phi(p)\cdots ϕϕϕ(p)⋯一会, ϕ ( p ) \phi(p) ϕ(p)的值就变成了 1 1 1。我们知道 1 1 1膜任何数都是 0 0 0,所以虽然有无穷个 2 2 2叠在一起,但是值是有限的,并且是一个定值。
所以我们就考虑递归求解。设 f ( p ) f(p) f(p)表示原结果膜 p p p的值,显然, f ( p ) = 2 f ( ϕ ( p ) ) + ϕ ( p ) % p f(p)=2^{f(\phi(p))+\phi(p)}\%p f(p)=2f(ϕ(p))+ϕ(p)%p。当 p = 1 p=1 p=1时,我们就返回0。
但是还有一点要注意,我筛就是筛到
1
e
6
1e6
1e6,如果
p
p
p在
1
e
6
1e6
1e6以上,就需要
O
(
p
)
O(\sqrt{p})
O(p)求一遍了。但是这样的过程不会进行多少次(经计算,不会超过4次)。
(当然如果你常数小的话,珂以筛到
1
e
7
1e7
1e7,就不怕
p
>
1
e
6
p>1e6
p>1e6的时候的暴力求了)
代码:
#include<bits/stdc++.h>
#define N 10010000
using namespace std;
namespace Flandle_Scarlet
{
int phi[N],primes[N];
bool notp[N];
void Init()//筛出phi
{
notp[1]=phi[1]=1;
int n=10000000;
int& cnt=primes[0];
for(int i=2;i<=n;++i)
{
if (!notp[i])
{
primes[++cnt]=i;
phi[i]=i-1;
}
for(int j=1;j<=cnt and i*primes[j]<=n;++j)
{
int u=primes[j];
notp[i*u]=1;
if (i%u==0)
{
phi[i*u]=u*phi[i];
break;
}
else
{
phi[i*u]=(u-1)*phi[i];
}
}
}
}
int smul(int a,int b,int m)//防爆的龟速乘
{
int r=0;
while(b)
{
if (b&1) r=(r+a)%m;
a=(a<<1)%m,b>>=1;
}
return r;
}
int qpow(int a,int b,int m)//快速幂
{
int r=1;
while(b)
{
if (b&1) r=smul(r,a,m);
a=smul(a,a,m),b>>=1;
}
return r;
}
int calc(int mod)//那个f函数,此处写成了calc
{
if (mod==1) return 0;
return qpow(2,calc(phi[mod])+phi[mod],mod)%mod;
}
void Query()
{
int T;scanf("%d",&T);
while(T--)
{
int m;scanf("%d",&m);
printf("%d\n",calc(m));
}
}
void Main()
{
Init();
Query();
}
}
int main()
{
Flandle_Scarlet::Main();
return 0;
}