zoukankan      html  css  js  c++  java
  • 算法笔记--数论模板小集(待增)

    gcd

    一行版:

    unsigned int gcd(unsigned int a,unsigned int b)
    {
        return b>0?gcd(b,a%b):a; 
    }

    快速幂和快速乘

    ll pow(ll n,ll k)
    {
        ll ans=1;
        while(k)
        {
            if(k%2) ans*=n;
            n*=n;
            k/=2;
        }
        return ans;
    }
    ll mul(ll n,ll k)
    {
        int ans=0;
        while(k)
        {
            if(k%2) ans+=n;
            n+=n;//n*=2;
            k/=2;
        }
        return ans;
    }

    扩展欧几里得(扩展gcd)

    int e_gcd(int a,int b,int &x,int &y)
    {
        if(!b)
        {
            x=1;
            y=0;
            return a;
        }
        int ans=e_gcd(b,a%b,x,y);
        int temp=x;
        x=y;
        y=temp-a/b*y;
        return ans;
    }
    int e_gcd(int a,int b,int &x,int &y){
        if (!b)
        {
            x=1,y=0;
            return a;
        }
        int ans=e_gcd(b,a%b,y,x);//注意x,y位置和上面不同
        y-=a/b*x;
        return ans;
    }

    乘法逆元

    扩展欧几里得版:

    ll e_gcd(ll a,ll b,ll &x,ll &y)
    {
        if(!b)
        {
            x=1;
            y=0;
            return a;
        }
        ll ans=e_gcd(b,a%b,x,y);
        ll temp=x;
        x=y;
        y=temp-a/b*y;
        return ans;
    }
    ll inv(ll a,ll n)
    {
        ll x,y,d=e_gcd(a,n,x,y);
        if(d==1)return (x%n+n)%n;
        else return -1;
    }

    费马小定理版:

    当模数不为质数时,是 a ^(phi(p) - 1)

    LL pow_mod(LL a, LL b, LL p){//a的b次方求余p 
         LL ret = 1;
         while(b){
             if(b & 1) ret = (ret * a) % p;
             a = (a * a) % p;
             b >>= 1;
         }
         return ret;
    }
    LL Fermat(LL a, LL p){//费马求a关于p的逆元 
             return pow_mod(a, p-2, p);
     }

    逆元递推版

    const int N = 200000 + 5;
    const int MOD = (int)1e9 + 7;
    int inv[N];
    int init(){
        inv[1] = 1;
        for(int i = 2; i < N; i ++){
            inv[i] = (MOD - MOD / i) * 1ll * inv[MOD % i] % MOD;
        }
    }

    普通素数筛(埃筛,复杂度O(nlog(log(n))))

    void prime(int n)
    {
        for(int i=2;i<=n;i++)
        {
            if(!not_prime[i])
            {
                for(int j=i+i;j<=n;j+=i)
                not_prime[j]=true;
            }
        }
    }

    线性素数筛欧拉筛,复杂度O(n))

    const int N=1e9+5;
    const int M=1e7+5;
    bool not_prime[N]={false};
    int prime[M];
    int tot;
    void euler_sieve(int n)
    {
        tot=0;
        for(int i=2;i<=n;i++)
        {
            if(!not_prime[i])prime[tot++]=i;
            for(int j=0;i*prime[j]<=n;j++)
            {
                not_prime[i*prime[j]]=true;
                if(i%prime[j]==0)break; //用最小的质因数筛,应为i%prime[j]==0,所以i=prime[j]*k,那么下一次循环要筛的是i*prime[j+1]=k*prime[j]*prime[j+1],没有必要筛,直接退出 
            }
        }
    }

    求单个欧拉函数

    ll Euler(ll n)
    {
        ll ans=n;
        for(ll i=2;i*i<=n;i++)
        {
            if(n%i==0)ans=ans/i*(i-1);
            while(n%i==0)n/=i;
        }
        if(n>1)ans=ans/n*(n-1);
        return ans;
    }

    普通筛法求欧拉函数(复杂度O(nlog(log(n))))

    void Euler(){
        phi[1] = 1;
        for(int i = 2; i < N; i ++){
            if(!phi[i]){
                for(int j = i; j < N; j += i){
                    if(!phi[j]) phi[j] = j;
                    phi[j] = phi[j] / i * (i-1);
                }
            }
        }
    }

    线性筛法求欧拉函数(复杂度O(n))

    void Euler(int n)
    {
        phi[1]=1;
        int k=0;
        for(int i=2;i<=n;i++)
        {
            if(!not_prime[i])
            {
                phi[i]=i-1;
                prime[k++]=i;
            }
            for(int j=0;i*prime[j]<=n;j++)
            {
                not_prime[i*prime[j]]=true;
                if(i%prime[j]==0)//根据欧拉函数的性质。 
                {
                    phi[i*prime[j]]=phi[i]*prime[j];
                    break;
                }
                else phi[i*prime[j]]=phi[i]*phi[prime[j]];
            }
        }
    }

    线性筛求莫比乌斯反演函数(复杂度O(n))

    void Mobius()
    {
        mem(vis,false);
        mu[1]=1;
        cnt=0;
        for(int i=2;i<N;i++)
        {
            if(!vis[i])
            {
                prime[cnt++]=i;
                mu[i]=-1;
            }
            for(int j=0;j<cnt&&i*prime[j]<N;j++)
            {
                vis[i*prime[j]]=true;
                if(i%prime[j])mu[i*prime[j]]=-mu[i];
                else
                {
                    mu[i*prime[j]]=0;
                    break;
                }
            }
        }
    }

    中国剩余定理:

    int ex_gcd(int a,int b,int &x,int &y)
    {
        if(b==0)
        {
            x=1;
            y=0;
            return a;
        }
        int ans=ex_gcd(b,a%b,y,x);
        y-=a/b*x;
        return ans;
    }
    int CRT(int a[],int m[],int n)
    {
        int M=1;
        int ans=0;
        for(int i=1;i<=n;i++)M*=m[i];
        for(int i=1;i<=n;i++)
        {
            int x,y;
            int Mi=M/m[i];
            ex_gcd(Mi,m[i],x,y); 
            ans=(ans+a[i]*Mi*x)%M;
        }
        if(ans<0)ans+=M;
        return ans;
    }

    米勒罗宾素数测试

    ll mod_qmul(ll n,ll k,ll mod)
    {
        ll ans=0;
        while(k)
        {
            if(k&1)ans=(ans+n)%mod;
            n=(n+n)%mod;
            k>>=1;
        }
        return ans;
    } 
    
    ll mod_qpow(ll n,ll k,ll mod)
    {
        ll ans=1;
        while(k)
        {
            if(k&1)ans=mod_qmul(ans,n,mod);
            n=mod_qmul(n,n,mod);
            k>>=1;
        }
        return ans;
    }
    
    bool check(ll a,ll n,ll x,ll t) 
    {
        ll ret=mod_qpow(a,x,n);
        ll last=ret;
        for(int i=0;i<t;i++)
        {
            ret=mod_qmul(ret,ret,n);
            if(ret==1&&last!=1&&last!=n-1)return true;
            last=ret;
        }
        if(ret!=1)return true;
        return false;
    }
    
    bool Miller_Rabin(ll n,int s)
    {
        if(n==2)return true;
        if(n<2||(n&1)==0)return false;
        ll x=n-1,t=0;
        while((x&1)==0)x>>=1,t++;
        for(int i=0;i<s;i++)
        {
            ll a=rand()%(n-1)+1;
            if(check(a,n,x,t))return false; 
        }
        return true;
    }

    卢卡斯定理求组合数

    void init()
    {
        fac[0]=1;
        for(int i=1;i<=p;i++)fac[i]=fac[i-1]*i%p;
    } 
    ll q_pow(ll n,ll k)
    {
        ll ans=1;
        while(k)
        {
            if(k&1)ans=ans*n%p;
            n=n*n%p;
            k>>=1;
        }
        return ans;
    }
    /*当p很大时*/ 
    ll C(ll n,ll m)
    {
        if(n<m)return 0;
        if(n-m<m)m=n-m;
        ll s1=1,s2=1;
        for(int i=0;i<m;i++) 
        {
            s1=s1*(n-i)%p;
            s2=s2*(i+1)%p;
        }
        return s1*q_pow(s2,p-2)%p;
    } 
    /*当p很小时 */
    ll C(ll n,ll m)
    {
        if(m>n)return 0;
        return fac[n]*q_pow(fac[m]*fac[n-m]%p,p-2)%p; 
    } 
    
    ll lucas(ll n,ll m)
    {
        if(m==0)return 1;
        return (C(n%p,m%p)*lucas(n/p,m/p))%p;
    }

    未完待续。。。

  • 相关阅读:
    Dos常用命令
    Typora的使用技巧
    Spring入门(2)
    (转)Oracle中判断某字段不为空及为空的SQL语句
    ReadOnly与Enabled
    邮件无法发送大文件,分卷压缩
    关于easyui checkbox 的一些操作处理
    JS 判断某变量是否为某数组中的一个值 的几种方法
    Oracle把逗号分割的字符串转换为可放入in的条件语句的字符数列
    C#区分大小写
  • 原文地址:https://www.cnblogs.com/widsom/p/7173095.html
Copyright © 2011-2022 走看看