2018 Multi-University Training Contest 8 1001 Character Encoding【容斥】

版权声明:学习,哪有那么多条条框框~ https://blog.csdn.net/Irish_Moonshine/article/details/81734666

http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1001&cid=809

题意:每个数字的取值范围为0到n-1,共有m个数字,求总和为k的方案数。

因为k的上限为1e5,那么我们不妨把k看做k个1,然后通过m-1个隔板来分割出m个数字。但是这么做会有一个问题,那就是数字可能为0。那么不妨将数字的取值范围改成1-n,m个数所以k要相应的变成k+m,那么就可以使用隔板法了。

先无限制的求一下总数:Cm+k1m1

如果我们现在拿出来n个1,将剩下的数分割成m个数,那么把这n个1放到任何位置上,都是至少有一个数字超出限制的。

也就是:Cm+k1m1Cm1Cm+k1nm1+Cm2Cm+k12nm1

如此反复直到不合法结束,到x结束也就是 到无法满足至少x个数超过限制时结束。

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <vector>
#include <algorithm>
using namespace std;
#define  LL long long

const LL N = 3e5 + 10;
const LL MAXN = 3e5;
const LL mod = 998244353;

LL fac[N];
LL inv[N];



LL qkm(LL base,LL mi)
{
    LL ans=1;
    while(mi){
        if(mi&1) ans=ans*base%mod;
        base=base*base%mod;
        mi>>=1;
    }
    return ans;
}

LL C(LL n,LL m)
{
    if(m>n) return 0;
    return fac[n]*inv[m]%mod*inv[n-m]%mod;
}

int main()
{

    fac[0]=fac[1]=1;

    for(LL i=2;i<=MAXN;i++)fac[i]=fac[i-1]*i%mod;

    inv[MAXN]=qkm(fac[MAXN],mod-2);

    for(LL i=MAXN-1;i>=0;i--)inv[i]=inv[i+1]*(i+1)%mod;
    LL T;
    cin>>T;
    while(T--){
        LL n,m,k;
        cin>>n>>m>>k;
        LL ans=C(k+m-1,m-1);
        LL p=1;
        LL di = k+m-1-n;
        LL num=1;
        while(di>=m-1){
            if(p){
                ans=ans-C(m,num)*C(di,m-1)%mod+mod;
                ans%=mod;
            }else{
                ans=ans+C(m,num)*C(di,m-1)%mod;
                ans%=mod;
            }
            p=p^1;
            num++;
            di-=n;
        }
        cout<<ans<<endl;
    }
    return 0;
}
阅读更多

没有更多推荐了,返回首页