模板

 一.数论 讲解

求单一欧拉函数 时间:O ( $\sqrt{n}$ )

int eular(int a)
{
    int ans=1;
    for(int i=2;i*i<=a;i++) {
        if(!(a%i)) {
            a/=i;
            ans*=i-1;
            for(;!(a%i);a/=i) ans*=i;
        }
    }
    if(a>1) ans*=a-1;
    return ans;
}
View Code

 

欧拉/莫比乌斯/质数线性筛 时间:O ( $n$ )

int pri[MN], priN, miu[MN], phi[MN],
bool ok[MN];
void init(int n = 1000000)
{
    phi[1] = miu[1] = 1;
    for(int i = 2; i <= n; i++)
    {
        if(!ok[i]) {pri[++priN] = i; phi[i] = i - 1; miu[i] = -1;}
        for(int j = 1, u;j <= priN && (u = pri[j] * i) <= MN;j++)
        {
            ok[u]=1;
            if(i%pri[j]) {
                phi[u] = phi[i] * (pri[j] - 1);
                miu[u] = -miu[i];
            } else {
                phi[u] = phi[i] * pri[j];
                miu[u] = 0;
                break;
            }
        }
    }
}
View Code

 

逆元线性筛(条件:模数为质数)时间:O ( $n$ )

typedef long long ll;
int inv[MN+5];
void init()
{
    inv[1]=1;
    for(int i=2;i<=MN;i++) inv[i]=(ll)(Mod-Mod/i)*inv[Mod%i]%Mod;
}
View Code

 

费马小定理求逆元(条件:模数为质数) 时间:O ( $\log_2Mod$ )

typedef long long ll;
int quipow(int a,int b,int Mod) //快速幂
{
    int ret=1;
    for(;b;b>>=1,a=(ll)a*a%Mod) if(b&1) ret=(ll)ret*a%Mod;
    return ret;
}
int getinverse(int x,int Mod) { //费马小定理 
    return quipow(x,Mod-2,Mod);
}
View Code

 

gcd(欧几里得算法) 时间:O ( $\log_2a$ )

int Gcd(int a,int b){return b==0?a:Gcd(b,a%b);}
View Code

 

exgcd(扩展欧几里得算法) 时间:O ( $\log_2a$ )

void exgcd(int a,int b,int&x,int&y)
{
    if(!b) x=1,y=0;
    else exgcd(b,a%b,y,x),y-=a/b*x;
}
View Code

 

exgcd求逆元 (条件:$\gcd(a,Mod)$ $=$ $1$ )  时间:O ( $\log_2a$ )

int getinverse(int x,int Mod) {
    int ans,y;
    exgcd(x,Mod,ans,y);
    return (ans%Mod+Mod)%Mod;
}
View Code

 

欧拉函数求逆元(条件:$\gcd(a,Mod)$ $=$ $1$ )  时间:O ( $\sqrt{a}$ )

int quipow(int a,int b,int Mod) //快速幂
{
    int ret=1;
    for(;b;b>>=1,a=(ll)a*a%Mod) if(b&1) ret=(ll)ret*a%Mod;
    return ret;
}
int eular(int a) //求欧拉函数
{
    int ans=1;
    for(int i=2;i*i<=a;i++) {
        if(!a%i) {
            a/=i;
            ans*=i-1;
            for(;a%i;a/=i) ans*=i;
        }
    }
    if(a>1) ans*=a-1;
    return ans;
}
int getinverse(int a,int Mod) { //欧拉函数求逆元
    return quipow(a,eular(Mod)-1,Mod);
}
View Code

 

bsgs(大步小步)(拔山盖世) (条件:$gcd(a,p)$ $=$ $1$) 时间:O( 哈希复杂度 $\times$ $\sqrt{Mod}$ )

int bsgs(int a,int b,int p) //a^x=b mod p
{
    std::map<int, int> h;
    if(b==1) return 0;
    int m=ceil(sqrt(p)),inv=getinverse(a,p),now=quipow(a,m-1,p),s;
    for(int i=m-1;i>=0;i--,now=(ll)now*inv%p) { //将b*a^(0~m-1)丢进hash表
        s=(ll)now*b%p;
        if(h.find(s)==h.end()) h.insert(P(s,i));
    }
    inv=quipow(a,m,p);now=1;
    for(int i=1;i<=m;i++) //在hash表里找与a^(i*m)相等的值
    {
        now=(ll)now*inv%p;
        if(h.find(now)!=h.end()) return i*m-h[now];
    }
    return -1;
}
View Code

 

exbsgs(扩展大步小步) 时间:O ( $\log_2a$ $+$ bsgs复杂度 )

int exbsgs(int a,int b,int p) //a^x=b mod p
{
    int k=0;
    for(int d=Gcd(a,p);d>1;d=Gcd(a,p)) //找到最小的k使得gcd(a,p/gcd(a^k,p))=1
    {
        if(b%d) return -1;
        b/=d;p/=d;
        b=(ll)b*getinverse(a/d,p)%p;
        k++;
    }
    int ans=bsgs(a,b,p);
    if(ans==-1) return -1;
    else return ans+k;
}
View Code

 

CRT(中国剩余定理/孙子定理)(条件:对于$\forall i,j , i \neq j$,$gcd(m_{i},m_{j}) = 1$) 时间:O ( $n$ $\cdot$ $\log_2m_{i}$ )

int CRT(int n,int *a,int *m) //X = a[i] mod m[i]
{
    int M=1,ans=0,w;
    for(int i=1;i<=n;i++) M*=m[i];
    for(int i=1;i<=n;i++) {
        w=M/m[i];
        ans=(ans+(ll)a[i]*w%M*getinverse(w,m[i])%M)%M;
    }
    return (ans%M+M)%M;
}
View Code

 

 Lucas定理 (条件:$p\in \mathbb{P}$) 时间:O ( $\log_pn$ $\cdot$ $\log_2p$ $+$ $p$ )

int C(int n,int m,int Mod) {
    if(m>n) return 0;
    return (ll)fac[n]*getinverse(fac[m],Mod)%Mod*getinverse(fac[n-m],Mod)%Mod;
}
int lucas(int n,int m,int p) //C(n,m) % p
{
    if(!m) return 1;
    return (ll)C(n%p,m%p,p)*lucas(n/p,m/p,p)%p;
}
View Code

 

exlucas(扩展lucas) 时间:设P质因数分解后为$ = p_{1}^{k_{1}} \cdot p_{2}^{k_{2}} \cdot .... \cdot p_{t}^{k_{t}}$,则复杂度为O ( CRT复杂度+$\sum_{i=1}^{t} p_{i}^{k_{i}} \cdot \log_{p_{i}}n$ )

int calc(int n,int p,int pt)
{
    if(!n) return 1;
    int ans=1;
    for(int i=2;i<=pt;i++) if(i%p) ans=(ll)ans*i%pt;
    ans=quipow(ans,n/pt,pt);
    for(int i=2;i<=n%pt;i++) if(i%p) ans=(ll)ans*i%pt;
    return (ll)ans*calc(n/p,p,pt)%pt;
}
int mutilucas(int n,int m,int p,int pt) //C(n,m) mod p^t
{
    int cnt=0;
    for(int i=n;i;i/=p) cnt+=i/p;
    for(int i=m;i;i/=p) cnt-=i/p;
    for(int i=n-m;i;i/=p) cnt-=i/p;
    return (ll)quipow(p,cnt,pt)*calc(n,p,pt)%pt*getinverse(calc(m,p,pt),pt)%pt*getinverse(calc(n-m,p,pt),pt)%pt;
}
int exlucas(int n,int m,int P) //C(n,m) mod P
{
    if(m>n) return 0;
    int cnt=0,p[40],a[40];
    for(int i=2;i*i<=P;i++)
    {
        if(P%i==0) {
            p[++cnt]=1;
            for(;P%i==0;) {
                P/=i;
                p[cnt]*=i;;
            }
            a[cnt]=mutilucas(n,m,i,p[cnt]);
        }
    }
    if(P>1) p[++cnt]=P,a[cnt]=mutilucas(n,m,P,P);
    return CRT(cnt,a,p);
}
View Code

 

 

posted @ 2019-02-02 16:00  zzpcd  阅读(179)  评论(0编辑  收藏  举报