【原创】数论模板-拓展欧几里得,质因数分解,快速幂快速加,欧拉函数筛法,欧拉函数求法,筛质数,卡塔兰数,筛逆元,第一二类斯特林数,米勒罗宾算法

版权声明:未经过作者允许,QωQ是可以转载的,只不过要赞一下本文章并发评论告诉我,然后转载附上原网址就好了!=QωQ= https://blog.csdn.net/c20182030/article/details/78333407
#include<ctime>
#include<cstdio>
#include<cstdlib>
const int MAXN=12345;

//拓展欧几里得:返回值=gcd(a,b),x,y满足a*x+b*y=gcd(a,b),a^x1(mod b) 即逆元
int exgcd(int a,int b,int &x,int &y)
{
    if(!b) 
    {
        x=1,y=0;
        return a;
    }
    int ans=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return ans;
}

//最大公因数和最小公倍数
int gcd(int a,int b)
{
    return b?gcd(b,a%b):a;
}

int lcm(int a,int b)
{
    return a*b/gcd(a,b);
}

//质因数分解
int cnt,Cr[MAXN],Cl[MAXN];
void cut(int x)
{
    for(int i=2;i*i<=x;i++)
        if(x%i==0)
        {
            Cr[++cnt]=i;
            while(x%i==0) Cl[cnt]++,x/=i;
        }
    if(x>1) Cr[++cnt]=x,Cl[cnt]=1;
}

//快速幂
int ksm(int a,int b,int c)
{
    int ans=1;
    a%=c;
    while(b)
    {
        if(b&1) (ans*=a)%=c;
        b>>=1; (a*=a)%=c;
    }
    return ans;
}

//慢速幂(快速加,以防爆intint mul(int a,int b,int c)
{
    int ans=0;
    while(b)
    {
        if(b&1) (ans+=a)%=c;
        b>>=1; (a+=a)%=c;
    }
    return ans;
}
int msm(int a,int b,int c)
{
    if(b==0) return 1;
    if(b==1) return a%c;
    int ans=msm(a,b/2,c)%c;
    ans=mul(ans,ans,c)%c;
    if(b%2) ans=mul(ans,a,c)%c;
    return ans%c;
}

//欧拉函数
int phi(int x)
{
    int k=x;
    for(int i=2;i*i<=x;i++)
        if(x%i==0)
        {
            while(x%i==0) x/=i;
            k=k/i*(i-1);
        }
    if(x>1) k=k/x*(x-1);
    return k;
}

//筛欧拉函数+筛质数
bool vis[MAXN];
int ct,eul[MAXN],p[MAXN];//p为质数数组,实际大小可以略大于MAXN/ln(MAXN)
void Shai(int N)
{
    for(int i=2;i<=N;i++)
    {
        if(!vis[i]) p[++ct]=i,eul[i]=i-1;
        for(int j=1;j<=ct&&p[j]*i<=N;j++)
        {
            vis[p[j]*i]=1;
            if(i%p[j]==0)   
            {  
                eul[p[j]*i]=eul[i]*p[j];  
                break;  
            }  
            eul[p[j]*i]=eul[i]*(p[j]-1);  
        }
    }
}

//生成N个元素的K排列
int lis[MAXN],Give[MAXN];
bool vi[MAXN];
void dfs1(int pos,int N,int K)
{
    if(pos>K)
    {
        for(int i=1;i<K;i++)
            printf("%d ",lis[i]);
        printf("%d\n",lis[K]);
        return ;
    }
    for(int i=1;i<=N;i++)
        if(!vi[i]) vi[i]=1,lis[pos]=i,dfs1(pos+1,N,K),vi[i]=0;
}

//卡特兰数
int Ctl[MAXN];
void Catalan(int N)
{
    Ctl[1]=1;
    for(int i=2;i<=N;i++)
        Ctl[i]=(4*i-2)/(i+1)*Ctl[i-1];
}

//筛1~N关于p的逆元
int ny[MAXN];
void ShaiNy(int N,int p)
{
    ny[1]=1;
    for(int i=2;i<=N;i++)
        ny[i]=-(p/i)*ny[p%i];
}

//MillerRobin判断素数
bool MillerRobin(int p)
{
    srand((unsigned)time(NULL));
    if(p==2||p==3) return true;
    if(p%2==0) return false;

    int N=50,cnt=0,q=p-1;

    while(!(q&1)) cnt++,q>>=1;
    while(N--)
    {
        bool helper=1;
        int a=rand()%(p-1)+1,v=ksm(a,q,p),k=cnt;
        if(v==1||v==p-1) continue;
        while(k--&&helper)
        {
            (v*=v)%=p;
            if(v==p-1) helper=0;
        }
        if(helper) return false;
    }
    return true;
}

//第一类stirling数,把n个数分成k个环排列
int S(int n,int k)
{
    if(!n||!k) return 0;
    if(k==1) return 1;
    return S(n-1,k-1)+(n-1)*S(n-1,k);
}

//第二类stirling数,把n个数的集合正好分为k个非空子集和
int S2(int n,int k)
{
    if(n<k||!k) return 0;
    if(n==k||k==1) return 1;
    return S2(n-1,k-1)+k*S2(n-1,k);
}

int main()
{

}

猜你喜欢

转载自blog.csdn.net/c20182030/article/details/78333407
今日推荐