BZOJ2219:数论之神 数论
BZOJ1494:[NOI2007]生成树计数 矩阵乘法+最小表示法+插头dp

BZOJ3884: 上帝与集合的正确用法 数论

shinbokuow posted @ Feb 28, 2015 07:25:17 PM in BZOJ with tags 数学 , 1402 阅读

首先我们知道欧拉定理:

\[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;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter