[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,'
');
	}
	return 0;
}
原文地址:https://www.cnblogs.com/PPLPPL/p/13625596.html