【BZOJ3884】上帝与集合的正确用法(欧拉定理,数论)
【BZOJ3884】上帝与集合的正确用法(欧拉定理,数论)
题面
题解
我们有欧拉定理:
当\(b \perp p\)时
\[a^b≡a^{b\%\varphi(p)}\pmod p
\]
否则
当\(b≥\varphi(p)\)时
\[a^b≡a^{b\%\varphi(p)+\varphi(p)}\pmod p
\]
这道题里面\(2\)的无穷次方显然会比\(\varphi(p)\)大
所以,递归调用这个公式
因此每次\(p\)都会变成\(\varphi(p)\)
所以,\(\varphi(p)\)必定会不断缩小
当其变成\(1\)的是否就不用再算下去了
直接返回\(0\)就好
回朔的时候快速幂算一下就可以啦
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
inline int read()
{
int x=0,t=1;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
ll phi(ll x)
{
ll ret=x;
for(int i=2;i*i<=x;++i)
if(x%i==0)
{
ret=ret/i*(i-1);
while(x%i==0)x/=i;
}
if(x>1)ret=ret/x*(x-1);
return ret;
}
ll fpow(ll a,ll b,ll p)
{
ll s=1;
while(b){if(b&1)s=1ll*s*a%p;a=1ll*a*a%p;b>>=1;}
return s;
}
ll Query(int P)
{
if(P==1)return 0;
ll x=phi(P);
return fpow(2,Query(x)+x,P);
}
int main()
{
int T=read();
while(T--)
printf("%lld\n",Query(read()));
return 0;
}