zoukankan      html  css  js  c++  java
  • 数论算法模板(不定期更新)

    /**********/
    
    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<cstdlib>
    #include<vector>
    #include<stack>
    #include<map>
    using namespace std;
    typedef long long ll;
    
    /***********GCD**********************/
    
    ll gcd(ll a,ll b)
    {
        if(b==0)
            return a;
        return gcd(b,a%b);
    }
    
    /*************快速乘***************/
    
    ll mult_mod(ll a,ll b,ll mod)
    {
        a%=mod; b%=mod;
        ll res=0;
        while(b)
        {
            if(b&1)
            {
                res+=a;
                res%=mod;
            }
            a<<=1;
            if(a>=mod) a%=mod;
            b>>=1;
        }
        return res;
    }
    
    /*************快速幂**************/
    
    ll pow_mod(ll x,ll n,ll mod)
    {
        if(n==1) return x%mod;
        x%=mod;
        ll t=x,res=1;
        while(n)
        {
            if(n&1) res=mult_mod(res,t,mod);
            t=mult_mod(t,t,mod);
            n>>=1;
        }
        return res;
    }
    
    /*****更快的*****快速幂***************/
    
    ll pow_mod(ll x,ll n,ll mod)
    {
        ll res=1;
        ll tmp=x%mod;
        while(n)
        {
            if(n&1)
            {
                res*=t;
                res%=mod;
            }
            n>>=1;
            t*=t;
            t%=mod;
        }
        return res;
    }
    
    /************扩展欧几里德****************/
    
    void extend_gcd(ll a,ll b,ll &x,ll &y)
    {
        ll d; //d=gcd(a,b)
        if(b==0)
        {
            x=1,y=0;
            d=a;
        }
        else
        {
            d=extend_gcd(b,a%b,y,x);
            ll xx=x,yy=y;
            x=yy;
            y=xx-(a/b)*yy;
        }
    }
    
    /************素数筛法******************/
    
    ll l,u,prime[N];
    int tot;
    int vis[N],ans[10000005];
    
    void isPrime()
    {
        tot=0;
        memset(vis,0,sizeof(vis));
        memset(prime,0,sizeof(prime));
        for(ll i=2;i<N;i++)
        {
            if(!vis[i])
            {
                prime[tot++]=i;
                for(ll j=i*i;j<N;j+=i)
                    vis[j]=1;
            }
        }
    }
    
    /******更快的*素数筛选*******************/
    
    const int MAXN=10000;
    int prime[MAXN+1];
    void isPrime()
    {
        memset(prime,0,sizeof(prime));
        //素数存储从下标1开始,prime[0]记录素数个数
        for(int i=2;i<=MAXN;i++)
        {
            if(!prime[i])
                prime[++prime[0]]=i;
            for(int j=1;j<=prime[0]&&prime[j]<=MAXN/i;j++)
            {
                prime[prime[j]*i]=1;
                if(i%prime[j]==0)
                    break;
            }
        }
    }
    
    /*********素数判定Miller_Rabin***********/
    
    bool test(ll a,ll n) //Miller_Rabin算法的核心
    {
        ll x=n-1,t=0,res,last;
        while((x&1)==0)
        {
            x>>=1;
            t++;
        }
        last=pow_mod(a,x,n);
    
        for(int i=0;i<t;i++)
        {
            res=pow_mod(last,2,n);
            if(res==1&&last!=1&&last!=n-1)
                return true;
            last=res;
        }
        if(res!=1) return true;
        return false;
    }
    
    bool millier_rabin(ll n)
    {
        if(n==2) return true;
        if(n==1||(n&1)==0) return false;
        for(int i=0;i<times;i++)
        {
            ll a=rand()%(n-1)+1;
            if(test(a,n))
                return false;
        }
        return true;
    }
    
    /*******质因数分解********************/
    
    ll factor[100][2];
    int cnt;
    //分解质因数:A=(p1^a1)*(p2^a2)*...*(pn^an)
    //factor[i][0]=pi,factor[i][1]=ai;
    void getFactor(ll x)
    {
        cnt=0;
        ll t=x;
        for(int i=0;prime[i]<=t/prime[i];i++)
        {
            factor[cnt][1]=0;
            while(t%prime[i]==0)
            {
                factor[cnt][0]=prime[i];
                while(t%prime[i]==0)
                {
                    factor[cnt][1]++;
                    t/=prime[i];
                }
                cnt++;
            }
        }
        if(t!=1)
        {
            factor[cnt][0]=t;
            factor[cnt][1]=1;
            cnt++;
        }
    }
    
    /*********大数因数分解Pollard_rho*************/
    
    ll pollard_rho(ll x,ll c)
    {
        ll x0,y,i=1,k=2;
        x0=rand()%x;
        y=x0;
        while(1)
        {
            i++;
            x0=(mult_mod(x0,x0,x)+c)%x;
            ll d=gcd(y-x0,x);
            if(d>1&&d<x) return d;
            if(y==x0) break;
            if(i==k)
            {
                y=x0;
                k+=k;
            }
        }
        return x;
    }
    
    void find_fac(ll n,int c)
    {
        if(n==1) return;
        if(millier_rabin(n))
        {
            factor[tot++]=n;
            return;
        }
        ll p=n;
        while(p>=n)
            p=pollard_rho(p,c--);
        find_fac(p,c);
        find_fac(n/p,c);
    }
    
    /**********正约数和(二分求法)**************/
    
    //将A进行因式分解可得:A = p1^a1 * p2^a2 * p3^a3 * pn^an
    //A^B=p1^(a1*B)*p2^(a2*B)*...*pn^(an*B);
    //A^B的所有约数之和sum=[1+p1+p1^2+...+p1^(a1*B)]*[1+p2+p2^2+...+p2^(a2*B)]*[1+pn+pn^2+...+pn^(an*B)].
    //等比数列1+pi+pi^2+pi^3+...+pi^n可以由二分求得(即将需要求解的因式分成部分来求解)
    //若n为奇数,一共有偶数项,则
    //1+p+p^2+p^3+........+p^n=(1+p+p^2+....+p^(n/2))*(1+p^(n/2+1));
    //若n为偶数,一共有奇数项,则
    //1+p+p^2+p^3+........+p^n=(1+p+p^2+....+p^(n/2-1))*(1+p^(n/2+1))+p^n/2;
    
    ll sum(ll p,ll n)
    {
        if(p==0) return 0;
        if(n==0) return 1;
        if(n&1)
            return ((1+pow_mod(p,n/2+1))%MOD*sum(p,n/2)%MOD)%MOD;
        else
            return ((1+pow_mod(p,n/2+1))%MOD*sum(p,n/2-1)+pow_mod(p,n/2)%MOD)%MOD;
    }
    
    /**********欧拉函数**********************/
    
    int Euler(int n)
    {
        int res=n;
        for(int i=2;i*i<=n;i++)
        {
            while(n%i==0)
            {
                n/=i; res-=(res/i);
                while(n%i==0)
                    n/=i;
            }
        }
        if(n>1)
           res-=(res/n);
        return res;
    }
    
    /******素数筛法+欧拉打表**********/
    
    ll e[N+5],p[N+5];
    bool vis[N+5];
    
    void init()
    {
        memset(e,0,sizeof(e));
        memset(p,0,sizeof(p));
        memset(vis,false,sizeof(vis));
        ll i,j;
        p[0]=1;//记录素数总个数
        p[1]=2;
    
        for(i=3;i<N;i+=2)
        {
            if(!vis[i])
            {
                p[++p[0]]=i;
                for(j=i*i;j<N;j+=i)
                    vis[j]=true;
            }
        }
    
        e[1]=1;
        for(i=1;i<=p[0];i++)
            e[p[i]]=p[i]-1; //为什么要-1?
    
        for(i=2;i<N;i++)
        {
            if(!e[i])
            {
                for(j=1;j<=p[0];j++)
                {
                    if(i%p[j]==0)
                    {
                        if(i/p[j]%p[j])
                            e[i]=e[i/p[j]]*e[p[j]];
                        else
                            e[i]=e[i/p[j]]*p[j];
                        break;
                    }
                }
            }
        }
    }
    
    /*************欧拉打表*更快版***************/
    
    #define N 1000000
    
    int e[N+5];
    void init()
    {
        int i,j;
        memset(e,0,sizeof(e));
        for(i=2;i<=N;i++)
        {
            if(!e[i])
            {
                for(j=i;j<=N;j+=i)
                {
                    if(!e[j])
                        e[j]=j;
                    e[j]=e[j]/i*(i-1);
                }
            }
        }
    }
    
    /**********容斥原理*二进制解法**************/
    
    vector<int> v;
    ll solve(int l,int r,int n) //[l,r]内与n互素的数字个数
    {
        v.clear();
        //筛选素数
        for(int i=2;i*i<=n;i++)
        {
            if(n%i==0)
            {
                v.push_back(i);
                while(n%i==0)
                    n/=i;
            }
        }
        if(n>1)
            v.push_back(n);
    
        //容斥原理的二进制解法
        int len=v.size();
        ll res=0;
        for(int i=1;i<(1<<len);i++)
        {
            int cnt=0;
            ll val=1;
            for(int j=0;j<len;j++)
            {
                if(i&(1<<j))
                {
                    cnt++;
                    val*=v[j];
                }
            }
            if(cnt&1) //若为奇数项进行加法,偶数项进行减法
                res+=r/val-(l-1)/val;
            else res-=r/val-(l-1)/val;
        }
        return r-l+1-res;
    }
  • 相关阅读:
    【NOIP 2003】 加分二叉树
    【POJ 1655】 Balancing Act
    【HDU 3613】Best Reward
    【POJ 3461】 Oulipo
    【POJ 2752】 Seek the Name, Seek the Fame
    【POJ 1961】 Period
    【POJ 2406】 Power Strings
    BZOJ3028 食物(生成函数)
    BZOJ5372 PKUSC2018神仙的游戏(NTT)
    BZOJ4836 二元运算(分治FFT)
  • 原文地址:https://www.cnblogs.com/atmacmer/p/5285810.html
Copyright © 2011-2022 走看看