前言
挺好一道数学题,适合我这种数学刚入门的蒟蒻做
题目
题目大意:给定正整数(n,m,k)
求(x_1+x_2+...+x_m=k (0 le x_i<n))的解的个数
答案对(998244353)取模
讲解
首先我们考虑如果没有(x_i<n)这个限制,答案应该是多少
明显可以用隔板法求出答案为(C(k+m-1,m-1))
接下来我们考虑减掉不合法的方案数
对于恰好有一个数不合法,两个数不合法...都要减掉
明显这很麻烦,所以很容易想到容斥
我们只需钦定(i)个数不合法,给它们在最开始便加上(n)即可
此时的方案数为(C(m,i)),剩余的(k-n*i)我们可以用隔板法求出方案数,然后再乘上容斥系数即可
所以对于一个确定的(i),它对答案的贡献为((-1)^{i} * C(m,i) * C(k-n*i+m-1,m-1))
注意:
1.你细品(C(k-n*i+m-1,m-1))的式子,仔细想想预处理阶乘的数组要开多大
2.最后的答案可能是负数,记得处理
代码
LL qpow(LL x,LL y,int MOD)
{
LL ret = 1;y %= (MOD-1);
while(y){if(y & 1) ret = ret * x % MOD;x = x * x % MOD;y >>= 1;}
return ret;
}
int fac[MAXN],ifac[MAXN];
void pre(int x)
{
fac[0] = 1;
for(int i = 1;i <= x;++ i) fac[i] = 1ll * fac[i-1] * i % MOD;
ifac[x] = qpow(fac[x],MOD-2,MOD);
for(int i = x-1;i >= 0;-- i) ifac[i] = 1ll * ifac[i+1] * (i+1) % MOD;
}
LL C(LL x,LL y)
{
if(x < y) return 0;
return 1ll * fac[x] * ifac[y] % MOD * ifac[x-y] % MOD;
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
pre(200000);
for(int T = Read(); T ;T --)
{
n = Read(); m = Read(); k = Read();
//x1+x2+..xm=k xi<n
LL ans = 0;
for(int i = 0;i <= m;++ i)
{
LL f = (i&1) ? -1 : 1;
ans = (ans + f * C(m,i) * C(k-n*i+m-1,m-1) % MOD) % MOD;
}
Put((ans + MOD) % MOD,'
');
}
return 0;
}