多校 HDU 6397 Character Encoding (容斥原理

若x1,x2,…..xn均大于等于0,则x1+x2+…+xm=k的方案数是C(k+m-1,m-1)种
好比有k个小球,放到m个盒子里,每个盒子不能为空,问有多少种放法。这里保证每个小球都是相同的,并且k>=m。分到m个盒子里,就等价于用m-1个板去隔开这k个球。
因为不能有空的盒子,所以板就必须插在两个球之间,一共有k-1个空,那么答案就是从x-1个空中挑出m-1个来插板:C(k-1,m-1)。
如果允许有空盒子出现,就相当于额外拿来m个球,像之前一样求不允许有空盒子的情况数,然后从每个盒子拿出一个球,即是有空盒子的情况数:C(m+k-1,m-1)
答案里会有某些Xi>=n,我们应该把这些情况去掉。
当有一个Xi>=n的时候,有C(m,1)种Xi。此时就相当于k个小球中,已经有n个小球放到了某个盒子里,接下来把剩下的k-n个小球放到m个盒子里就是有这么多种情况C(m+k-n-1,m-1)。
所以我们用C(m+k-1,m-1)-C(m,1)*C(m+k-n-1)^(m-1),这里面y(y>=2)个Xi>=n有重复的情况,但是y=1没有重复的情况,我们就可以加上C(m,2)*C(m+k-2*n-1)^(m-1)(这时仅一个的和仅两个的已经被完全减去了,同理处理到最后即可)

套用组合数模板进行计算即可
但是这里要注意数组要开大点,不然会wa

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e5+100;
const ll mod=998244353;
ll inv[maxn],fac[maxn],ans[maxn],pos[maxn];
ll qpow(ll a,int b)
{
    ll ans=1;
    a%=mod;
    while(b)
    {
        if(b&1)
            ans=(ans*a)%mod;
        a=(a*a)%mod;
        b/=2;
    }
    return ans;
}
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 C(int n,int k)
{
    if (k < 0 || k > n) return 0;
    return fac[n]*inv[k]%mod *inv[n-k]%mod;
}
int main()
{
    ll n,m,k,ans;
    int T;
    pre();
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld%lld",&n,&m,&k);
        ll ans=0;
        for(int c=0;c*n<=k;c++)
        {
            if(c&1)ans=(ans-C(m,c)*C(k-c*n-1+m,m-1)%mod+mod)%mod;
            else ans=(ans+C(m,c)*C(k-c*n-1+m,m-1)%mod)%mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
posted @ 2018-08-16 11:46  ffgcc  阅读(103)  评论(0编辑  收藏  举报