组合数取模专题/质因分解

T^TOJ 组合数取模

乘法逆元知识

组合计数-插板法

类型0:n,m<=1000 直接暴力预处理杨辉三角,预处理复杂度O(n*n) 公式:C(n,m)=C(n,n-m)=C(n-1,m-1)+C(n-1,m)

类型1:n,m<=1e6   且模数p是质数。   O(n)预处理 阶乘fac[i]和阶乘的逆ifac即可。然后 C(n,m)=fac[n]*ifac[m]*ifac[n-m]

预处理复杂度O(n),查询O(1)。HDU6333 Problem B. Harvest of Apples 莫队算法+逆元

类型2:n,m <=1e9 且模数p为质数,且p<=1e5,用Lucas定理,展开成多个组合数的乘积。

单次查询复杂度O(p*log(n)/log(p))  HDU3037 Saving Beans Lucas 定理+逆元

类型3:n<=1e9,m<=1e5, p<=1e9且为质数,用逆元暴力计算C(n,m)=n*(n-1)*(n-2)*……*(n-m+1)/(1*2*……*m)

算法复杂度O(m)

类型4: n,m<=1e5,mod非质数, 对阶乘分解质因数,然后跑快速幂,算法复杂度O(n)

图片.png

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e6+1;
const long long MOD=1e9+7;
int prim[MAX],fac[MAX];
void prime()
{
    memset(prim,0,sizeof(prim));
    for(int i=2;i<MAX;i++)
    {
        if(!prim[i]) prim[++prim[0]]=i;
        for(int j=1;j<=prim[0]&&prim[j]<=MAX/i;j++)
        {
            prim[prim[j]*i]=1;
            if(i%prim[j]==0) break;
        }
    }
}
void factor(int a,int b)
{
    memset(fac,0,sizeof(fac));int i;
    for(i=1;i<=prim[0]&&prim[i]<=a;i++)
    {
        int tmp=a;
        while(tmp)
        {
            fac[i]+=tmp/prim[i];
            tmp/=prim[i];
        }
    }
    fac[0]=i;
    for(i=1;i<=prim[0]&&prim[i]<=b;i++)
    {
        int tmp=b;
        while(tmp)
        {
            fac[i]-=tmp/prim[i];
            tmp/=prim[i];
        }
    }
    for(i=1;i<=prim[0]&&prim[i]<=a-b;i++)
    {
        int tmp=a-b;
        while(tmp)
        {
            fac[i]-=tmp/prim[i];
            tmp/=prim[i];
        }
    }
}
long long pow(long long a,int k,long long mod)//快速幂取模
{
    long long b=1;
    while(k)
    {
        if(k&1) b=b*a%mod;
        a=a*a%mod;
        k>>=1;
    }
    return b;
}
long long C(int a,int b)
{
    factor(a,b);
    long long c=1;
    for(int i=1;i<fac[0];i++) if(fac[i]) c=c*pow(prim[i],fac[i],MOD)%MOD;
    return c;
}
int main()
{
    int n,m;
    prime();
    while(~scanf("%d%d",&n,&m))
        printf("%I64d\n",C(n,m));
    return 0;
}

 附 大数质因分解

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+1;
int prim[MAX],fac[MAX][2],facnt;
void prime()
{
    memset(prim,0,sizeof(prim));
    for(int i=2;i<MAX;i++)
    {
        if(!prim[i]) prim[++prim[0]]=i;
        for(int j=1;j<=prim[0]&&prim[j]<=MAX/i;j++)
        {
            prim[prim[j]*i]=1;
            if(i%prim[j]==0) break;
        }
    }
}
int factor(long long x)
{
    memset(fac,0,sizeof(fac));facnt=0;
    long long tmp=x;
    for(int i=1;prim[i]<=tmp/prim[i];i++)
    {
        fac[facnt][1]=0;
        if(tmp%prim[i]==0)
        {
            fac[facnt][0]=prim[i];
            while(tmp%prim[i]==0)
            {
                fac[facnt][1]++;
                tmp/=prim[i];
            }
            facnt++;
        }
    }
    if(tmp!=1)
    {
        fac[facnt][0]=tmp;
        fac[facnt++][1]=1;
    }
    return facnt;
}
int main()
{
    prime();
    factor(1024*1000);
    printf("");
    return 0;
}

类型5:

类型6: 中国剩余定理+lucas

猜你喜欢

转载自blog.csdn.net/Nrtostp/article/details/81698388