前置芝士——欧拉定理:
若正整数(a,n)互质,则(a^{phi(n)}equiv1~(mod~n)),其中(phi(n))为欧拉函数
证明:
设小于(n)且与(n)互质的数构成的集合(即简化剩余系)为{(a_1,a_2,a_3...a_{phi(n)})},对于(forall a_i,a_j),若(a_i,a_j)在同一同余类时,有(~a imes a_iequiv~a imes a_j~(mod~n)),则(a imes(a_i-a_j)equiv~0~(mod~n)),又因为(a)与(n)互质,所以(a_i-a_jequiv0),即(a_iequiv~a_i)。因此,当(a_i)与(a_j)不在同一同余类时,(a!a_i,a!a_j) 也在不同的同余类。
又因为简化剩余系关于模(n)乘法封闭,故(a!a_i,a!a_j)也在这个简化剩余系中。因此,集合{(a_1,a_2...a_{phi(n)})}和集合{({a!a_1,a!a_2...a!a_{phi(n)}})}都可以表示(n)的简化剩余系,因此:
[a^{phi(n)}a_1a_2...a_{phi(n)}equiv(a!a_1)(a!a_2)...(a!a_{phi(n)})~(mod~n)
]
[Rightarrow~a^{phi(n)}a_1a_2...a_{phi(n)}equiv~a_1a_2...a_{phi(n)}~(mod~n)
]
[Rightarrow a^{phi(n)}equiv~1~(mod~n)
]
证毕
正题:拓展欧拉定理
当我们求(a^b(mod~p))时,最常用的应该就是快速幂了吧?但,如果(ble10^{100})呢?如果(ble10^{20000000})呢(见模板)?
这个时候,不仅(long~long)不够,快速幂也不够了。。
所以,又一个神奇的定理出现了!
它大概分以下三种情况
[a^bequivleft{egin{aligned}a^{b\%phi(n)}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~gcd(a,n)=1\a^b~~~~~~~~~~~~~~~~~~~gcd(a,n)
eq1&b<phi(n)\a^{b\%phi(n)+phi(n)}~~~~gcd(a,n)
eq1&bgephi(n)end{aligned}
ight.
]
第一种情况:
证明:
设(b=q imesphi(n)+r),其中(0le r<phi(n)),即(r=bmodphi(n))。
故:
[a^bequiv a^{q imesphi(n)+r}equiv (a^{phi(n)})^q imes a^requiv1^q imes a^requiv a^{bmodphi(n)}
]
证毕
第二种情况:废话
第三种情况:咕咕咕~~ (有能力的读者可以自己证明啦 (就是我不会))
有一个公理说明:这东西你虽然不知道它怎么来的,但知道怎么用就行。
OK,咱们来实践,上例题!
例题:P4139 上帝与集合的正确用法
一句话题意:(2^{2^{2...}}\%~p)
都不需要怎么引入了,看到的第一眼就知道是个拓展欧拉定理,但问题是如何求(2^{2^{2...}}\%~phi(p)+phi(p))。
但你们观察这个式子(2^{2^{2...}}\%~phi(p)+phi(p)),把中间的(2^{2^{2...}}\%~phi(p))拿出来,把它看作一个整体,又变成了(2^{2^{2...}}\%~p).
然后我们就可以递归直到(p)变为(0),再每次加回(phi(p)),就A了。
所以先用线性筛预处理出所有的(phi(p)),然后递归,本题就完事了。。
手起,码落
#include<bits/stdc++.h>
#define re register
using namespace std;
const int N=1e7+5;
int E[N],T;
void euler(int MAXN)
{
E[1]=1;
for(int i=2;i<=MAXN;i++)
{
if(!E[i])
for(int j=i;j<=MAXN;j+=i)
{
if(!E[j])E[j]=j;
E[j]=E[j]/i*(i-1);
}
}
}
inline int Pow(int x,int y,int mod)
{
re int sum=1;
for(;y;y>>=1,x=(1ll*x*x)%mod)
if(y&1)sum=(1ll*sum*x)%mod;
return sum;
}
inline int print(int x)
{
if(x==1)return 0;
return Pow(2,print(E[x])+E[x],x);
}
int main()
{
re int p;
euler(N-5);
scanf("%d",&T);
while(T--)
{
scanf("%d",&p);
printf("%d
",print(p));
}
return 0;
}