[笔记] 欧拉定理
欧拉定理的内容:
当\(a>\varphi(m)\)时,\(x^a \equiv x^{(a \ mod \ \varphi(m))+\varphi(m)} \ (mod \ m)\)。
当\(x和m\)互质时,\(x^{\varphi(m)}\equiv 1\),很多地方讲欧拉定理的时候只有这一条,实际上上面那一条也是欧拉(降幂)定理的内容。
证明:
咕咕咕(建议直接把公式背下来)
例题:
求\(x^{x^{x^x \cdots}}\)(无限个x)对\(y\)取模的值,t组数据。
解法:
令\(f(x,y)\)表示\(x,y\)的答案,当y为1时,显然答案为0。否则根据欧拉定理:\(x^{x^{x^x \cdots}} \equiv x^{(x^{x^x \cdots} \ mod \ \varphi(y))+\varphi(y)}\ mod \ y\)。\(x^{x^x \cdots} \ mod \ \varphi(y)\)可以递归求解,发现最终y一定会变成1从而结束递归。递归次数是\(log(y)\)级别的,因为众所周知对于>2的整数n,\(\varphi(n)\)一定是偶数,所以如果y是奇数,\(\varphi(y)\)一定会是偶数;而如果y是偶数,则\(\varphi(y)\)最多是y的一半(因为至少有一半的数都和y有共同的因数2)。
点击查看代码
#include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<n;++i)
#define repn(i,n) for(int i=1;i<=n;++i)
#define LL long long
#define pii pair <int,int>
#define pb push_back
#define fi first
#define se second
#define mpr make_pair
using namespace std;
LL qpow(LL x,LL a,LL MOD)
{
LL res=x,ret=1;
while(a>0)
{
if((a&1)==1) ret=ret*res%MOD;
a>>=1;
res=res*res%MOD;
}
return ret;
}
LL phi[20000010];
bool isp[20000010];
vector <LL> pri;
void sievePhi()
{
for(LL i=2;i<=20000000;++i) isp[i]=true;
for(LL i=2;i<=20000000;++i)
{
if(isp[i]) pri.pb(i),phi[i]=i-1;
rep(j,pri.size())
{
if(pri[j]*i>20000000) break;
isp[pri[j]*i]=false;
if(i%pri[j]!=0) phi[i*pri[j]]=phi[i]*(pri[j]-1);
else
{
phi[i*pri[j]]=phi[i]*pri[j];
break;
}
}
}
}
LL t,x,y;
//x^a=x^(a%phi[m]+phi[m]) (%m)
LL dfs(LL xx,LL yy)//xx^xx^xx... %yy
{
if(yy==1) return 0;
LL pw=dfs(xx,phi[yy])+phi[yy];
return qpow(xx,pw,yy);
}
int main()
{
//freopen("power.in","r",stdin);
//freopen("power.out","w",stdout);
sievePhi();
cin>>t;
rep(tn,t)
{
cin>>x>>y;
if(x==1) cout<<1%y<<endl;
else cout<<dfs(x,y)<<endl;
}
return 0;
}