拓展欧拉定理浅谈
前置芝士——欧拉定理:
若正整数\(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\times a_i\equiv~a\times a_j~(mod~n)\),则\(a\times(a_i-a_j)\equiv~0~(mod~n)\),又因为\(a\)与\(n\)互质,所以\(a_i-a_j\equiv0\),即\(a_i\equiv~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)\)时,最常用的应该就是快速幂了吧?但,如果\(b\le10^{100}\)呢?如果\(b\le10^{20000000}\)呢(见模板)?
这个时候,不仅\(long~long\)不够,快速幂也不够了。。
所以,又一个神奇的定理出现了!
它大概分以下三种情况
\[a^b\equiv\left\{\begin{aligned}a^{b\%\phi(n)}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\gcd(a,n)=1\\a^b~~~~~~~~~~~~~~~~~~~\gcd(a,n)\neq1\&b<\phi(n)\\a^{b\%\phi(n)+\phi(n)}~~~~\gcd(a,n)\neq1\&b\ge\phi(n)\end{aligned}\right.
\]
第一种情况:
证明:
设\(b=q\times\phi(n)+r\),其中\(0\le r<\phi(n)\),即\(r=b\mod\phi(n)\)。
故:
\[a^b\equiv a^{q\times\phi(n)+r}\equiv (a^{\phi(n)})^q\times a^r\equiv1^q\times a^r\equiv a^{b\mod\phi(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\n",print(p));
}
return 0;
}