BZOJ3884: 上帝与集合的正确用法 数论
首先我们知道欧拉定理:
\[a^{\phi(p)}=1(mod~p)((a,p)=1)\]
那么看起来这道题有点能做了.
可惜如果\(p\)是偶数又怎么办?
我们有\(cx%cy=c(x%y)\)这条神奇的性质.也很容易证明.
这样,我们就可以将问题递归处理了.
对于\(\phi\)函数的不断迭代是\(log\)级别的,然后我们每次\(O(\sqrt{n}logn)\)求\(\phi\).因此时间复杂度为\(O(\sqrt{n}logn)\).
还有另外一种不用讨论的方法:
有公式:\(a^x=a^{x\%\phi(p)+\phi(p)}(mod~p)(x>=\phi(p))\)
这样就能更加自然地递归下去了.
#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
inline int getphi(int x){
int re=x,t=x;
for(int i=2;i*i<=x;++i){
if(t%i==0){
re=(LL)re*(i-1)/i;
while(t%i==0)t/=i;
}
}if(t!=1)re=(LL)re*(t-1)/t;
return re;
}
inline int ksm(int x,int y,int p){
int re=1,t=x;for(;y;y>>=1,t=(LL)t*t%p)if(y&1)re=(LL)re*t%p;return re;
}
inline int calc(int p){
if(p==1)return 0;
else{
int phi=getphi(p),re=calc(phi);
return ksm(2,re+phi,p);
}
}
int main(){
int T,p;scanf("%d",&T);
while(T--){
scanf("%d",&p);
printf("%d\n",calc(p));
}
return 0;
}
评论 (0)