组合数

题目链接

885. 求组合数 I
886. 求组合数 II
887. 求组合数 IIIP3807 【模板】卢卡斯定理/Lucas 定理
888. 求组合数 IV

885. 求组合数 I

给定 \(n\) 组询问,每组询问给定两个整数 \(a,b\),请你输出 \(C_a^b\bmod(10^9+7)\) 的值。

输入格式

第一行包含整数 \(n\)

接下来 \(n\) 行,每行包含一组 \(a\)\(b\)

输出格式

\(n\) 行,每行输出一个询问的解。

数据范围

\(1≤n≤10000\),
\(1≤b≤a≤2000\)

输入样例:

3
3 1
5 3
2 2

输出样例:

3
10
1

\(C_i^j=C_{i-1}^{j}+C_{i-1}^{j-1}\)

  • 时间复杂度:\(O(n^2)\)

代码

#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int c[2005][2005];
void init()
{
    for(int i=0;i<=2000;i++)
        for(int j=0;j<=i;j++)
            if(!j)c[i][j]=1;
            else
                c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
int main()
{
    init();
    int n,a,b;
    for(scanf("%d",&n);n;n--)
    {
        scanf("%d%d",&a,&b);
        printf("%d\n",c[a][b]);
    }
    return 0;
}

886. 求组合数 II

给定 \(n\) 组询问,每组询问给定两个整数 \(a,b\),请你输出 \(C_a^b \bmod(10^9+7)\) 的值。

输入格式

第一行包含整数 \(n\)

接下来 \(n\) 行,每行包含一组 \(a\)\(b\)

输出格式

\(n\) 行,每行输出一个询问的解。

数据范围

\(1≤n≤10000\),
\(1≤b≤a≤10^5\)

输入样例:

3
3 1
5 3
2 2

输出样例:

3
10
1

\(C_a^b=\frac{a!}{b!(a-b)!}\)

  • 时间复杂度:\(O(nlog(mod))\)

代码

#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int n,a,b;
int fac[100005],inv_fac[100005];
int ksm(int a,int b)
{
    int res=1%mod;
    for(;b;b>>=1)
    {
        if(b&1)res=1ll*res*a%mod;
        a=1ll*a*a%mod;
    }
    return res;
}
void init()
{
    fac[0]=inv_fac[0]=1;
    for(int i=1;i<=100000;i++)fac[i]=1ll*i*fac[i-1]%mod,inv_fac[i]=1ll*inv_fac[i-1]*ksm(i,mod-2)%mod;
}
int main()
{
    init();
    for(scanf("%d",&n);n;n--)
    {
        scanf("%d%d",&a,&b);
        printf("%d\n",1ll*fac[a]*inv_fac[b]%mod*inv_fac[a-b]%mod);
    }
    return 0;
}

887. 求组合数 III

给定 \(n\) 组询问,每组询问给定三个整数 \(a,b,p\),其中 \(p\) 是质数,请你输出 \(C_a^b \bmod p\) 的值。

输入格式

第一行包含整数 \(n\)

接下来 \(n\) 行,每行包含一组 \(a,b,p\)

输出格式

\(n\) 行,每行输出一个询问的解。

数据范围

\(1≤n≤20\),
\(1≤b≤a≤10^{18}\),
\(1≤p≤10^5\),

输入样例:

3
5 3 7
3 1 5
6 4 13

输出样例:

3
3
2
  • 时间复杂度:\(O(T\times b\times log_pa\times log(mod))\)

代码

#include<bits/stdc++.h>
using namespace std;
using LL=long long;
int p,n;
LL a,b;
int ksm(int a,int b,int p)
{
    int res=1%p;
    for(;b;b>>=1)
    {
        if(b&1)res=1ll*res*a%p;
        a=1ll*a*a%p;
    }
    return res;
}
inline int C(int a,int b,int p)
{
    int res=1;
    for(int i=1,j=a;i<=b;i++,j--)
    {
        res=1ll*res*j%p;
        res=1ll*res*ksm(i,p-2,p)%p;
    }
    return res;
}
inline int lucas(LL a,LL b,int p)
{
    if(a<p&&b<p)return C(a,b,p);
    return 1ll*C(a%p,b%p,p)*lucas(a/p,b/p,p)%p;
}
int main()
{
    for(scanf("%d",&n);n;n--)
    {
        scanf("%lld%lld%d",&a,&b,&p);
        printf("%d\n",lucas(a,b,p));
    }
    return 0;
}

888. 求组合数 IV

输入 \(a,b\),求 \(C_b^a\) 的值。

注意结果可能很大,需要使用高精度计算。

输入格式

共一行,包含两个整数 \(a\)\(b\)

输出格式

共一行,输出 \(C_b^a\) 的值。

数据范围

\(1≤b≤a≤5000\)

输入样例:

5 3

输出样例:

10

高精度乘法,阶乘分解

设素数个数为 \(n\),每个素数平均出现次数为 \(m\),高精度乘法复杂度 \(O(t)\)

  • 时间复杂度:\(O(nmt)\)

代码

#include<bits/stdc++.h>
using namespace std;
int a,b;
int m,prime[5005],sum[1000];
int v[5005];
void primes(int n)
{
    for(int i=2;i<=n;i++)
    {
        if(!v[i])
        {
            v[i]=i;
            prime[++m]=i;
        }
        for(int j=1;j<=m;j++)
        {
            if(v[i]<prime[j]||i*prime[j]>n)break;
            v[i*prime[j]]=prime[j];
        }
    }
}
inline vector<int> mul(vector<int> A,int b)
{
    vector<int> C;
    int t=0;
    for(int i=0;i<A.size()||t;i++)
    {
        if(i<A.size())t+=A[i]*b;
        C.push_back(t%10);
        t/=10;
    }
    return C;
}
inline int get(int x,int p)
{
    int res=0;
    while(x)res+=x/p,x/=p;
    return res;
}
int main()
{
    scanf("%d%d",&a,&b);
    primes(a);
    for(int i=1;i<=m;i++)
    {
        int p=prime[i];
        sum[i]=get(a,p)-get(b,p)-get(a-b,p);
    }
    vector<int> res(1,1);
    for(int i=1;i<=m;i++)
        for(int j=0;j<sum[i];j++)
            res=mul(res,prime[i]);
    for(int i=res.size()-1;~i;i--)
        printf("%d",res[i]);
    return 0;
}
posted @ 2021-10-23 21:39  zyy2001  阅读(97)  评论(0编辑  收藏  举报