数论算法模板(不定期更新)

/**********/

#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;
}
posted @ 2016-03-17 00:15  &ATM  阅读(488)  评论(0编辑  收藏  举报
……