HDU - 6397 Character Encoding 2018 Multi-University Training Contest 8 (组合数学)

题意:问有多少种不重复的m个数,值在[0,n-1]范围内且和为k。

分析:当k<=n-1时,肯定不会有盒子超过n,结果是C(m+k-1,k);当k>m*(n-1)时,结果是0。

剩下的情况,可以转化为组合数学中的放球问题,球与球之间没有区别,盒子之间有区别且每个盒子不超过n-1个球。

根据容斥原理得,结果为signma((-1)^i * C(m,i) * C(m+k-i*p-1, k-i*n))

#include<bits/stdc++.h>
using namespace std;
const int mod = 998244353;
const int maxn = 2e5+5;
typedef long long LL;
LL fac[maxn],inv[maxn];
LL res[maxn];

LL qpow(LL b,int n){
    LL res=1;
    while(n){
        if(n&1) res=res*b%mod;
        b = b*b%mod;
        n>>=1;
    }
    return res;
}

void pre()
{
    fac[0]=fac[1]=1;
    for(int i=2;i<maxn;++i) fac[i]=i*fac[i-1]%mod;
    inv[maxn-1]=qpow(fac[maxn-1],mod-2);
    for(int i=maxn-2;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
}

LL Comb(int n,int k) {  
    if(n==k) return 1;
    else if(n<k) return 0;
    return fac[n]*inv[k]%mod *inv[n-k]%mod;
}

int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    pre();
    int T;
    scanf("%d",&T);
    while(T--){
        int N,M,k; scanf("%d%d%d",&N,&M,&k);
        if(k<=N-1)
            printf("%lld\n",Comb(M+k-1,k));
        else if(k>M*(N-1))
            printf("0\n");
        else{
            LL res=0;
            for(int i=0;i<=k/N;++i){
                if(i&1)
                    res = (res+mod-Comb(M,i)*Comb(M+k-1-i*N,k-i*N)%mod)%mod;
                else
                    res = (res+Comb(M,i)*Comb(M+k-1-i*N,k-i*N)%mod)%mod;
            }
            printf("%lld\n",res);
        }
    }
    return 0;    
}

猜你喜欢

转载自www.cnblogs.com/xiuwenli/p/9483331.html