多校 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;
}