[HDU6397] Character Encoding

前言

挺好一道数学题,适合我这种数学刚入门的蒟蒻做

题目

HDU

题目大意:给定正整数\(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,'\n');
	}
	return 0;
}
posted @ 2020-09-07 10:47  皮皮刘  阅读(180)  评论(0编辑  收藏  举报