题目链接
题意:给你一个1e7以内的模数,求2的无限次方模那个模数的结果。
题解:
如果一个东西的无限次方是可做的,那么我们应该考虑我们应该能在有限次得到结果。其实看到这种指数嵌套的东西很容易想到要用欧拉定理或者扩展欧拉定理吧,毕竟扩展欧拉定理很重要的一个应用就是解决这类问题。
扩展欧拉定理可以做
a
a
和不互质情况下的
ax%p
a
x
%
p
,当
x>=p
x
>=
p
时,有
ax=ax%ϕ(p)+ϕ(p)(mod p)
a
x
=
a
x
%
ϕ
(
p
)
+
ϕ
(
p
)
(
m
o
d
p
)
。于是我们用这个公式来解决这个问题。
我们要求
222…%p
2
2
2
…
%
p
,那么我们可以把它变为
222…%ϕ(p)+ϕ(p)
2
2
2
…
%
ϕ
(
p
)
+
ϕ
(
p
)
,然后依次递归下去,直到
ϕ(p)=1
ϕ
(
p
)
=
1
,那么任何数模1的结果都是0,就可以返回0了。这样不会无限次向下递归,我们来考虑一下递归次数,也就是这个算法的复杂度。
我们知道,一个偶数
x
x
比它小的偶数都与它不互质,所以它的值肯定小于等于
x2
x
2
。而一个奇数如果是质数,那么它的
ϕ
ϕ
值是
x−1
x
−
1
,是偶数,若不是质数,那么由于
ϕ
ϕ
是积性函数,那么
ϕ(x)
ϕ
(
x
)
肯定是由若干奇数的
ϕ
ϕ
相乘得来,也就是一些偶数的乘积,所以除了1以为的
ϕ(奇数)
ϕ
(
奇
数
)
都等于偶数。那么对于任何一个正整数,它要么是奇数,要么是偶数。我们对它往下递归两层,偶数直接就减小至少一半了,奇数第一层变成不大于原数的偶数,第二层再变为偶数的一半,所以往下递归两层至少能将其减小一半,所以最差复杂度也是
log p
l
o
g
p
级别的。
代码:
#include <bits/stdc++.h>
using namespace std;
int T,mod,p[10000010],phi[10000010],cnt,book[10000010];
inline int ksm(long long x,long long y,long long mod)
{
long long res=1;
while(y)
{
if(y&1)
res=(res*x)%mod;
x=(x*x)%mod;
y>>=1;
}
return res;
}
inline int cal(int mod)
{
if(mod==1)
return 0;
return ksm(2,cal(phi[mod])+phi[mod],mod);
}
int main()
{
phi[1]=1;
book[1]=1;
for(int i=2;i<=1e7;++i)
{
if(!book[i])
{
p[++cnt]=i;
phi[i]=i-1;
}
for(int j=1;j<=cnt&&p[j]*i<=1e7;++j)
{
book[i*p[j]]=1;
if(i%p[j]==0)
{
phi[i*p[j]]=phi[i]*p[j];
break;
}
else
phi[i*p[j]]=phi[i]*phi[p[j]];
}
}
scanf("%d",&T);
while(T--)
{
scanf("%d",&mod);
printf("%d\n",cal(mod));
}
return 0;
}