题目:http://acm.hdu.edu.cn/showproblem.php?pid=6397
题意:
m个桶,放k个小球,每个桶只能放0~n-1个球,求方案数
分析:
(1)由隔板法可知:
若没有少于n-1个的限制,则方案数为:C(k+m-1,m-1);
其实等价于,x1+x2+…+xm=k,(xi>=0)的解数
(2)接下来容斥:
考虑有i个桶违反了规定,放了>=n个;
此时对等式两边同时减去i个n,变成:
x1’+x2’+…+xm’=k-i*n,xj’=(xj < n? xj : xj-n)
这样就把违反规定的那i个桶的限制条件xj>=n变成了xj’>=0;
由(1)只,这个解的数量为C(k-i*n+m-1,m-1)
容斥系数为(-1)^i
注意预处理阶乘及其逆元
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
const int tmax=2e5+5;
ll ans,jie[tmax],rev[tmax];
int n,m,k;
ll quick_pow(ll x)
{
ll k=mod-2,sum=1;
while(k>0)
{
if(k&1) sum=sum*x%mod;
x=x*x%mod;
k>>=1;
}
return sum;
}
void init()
{
jie[0]=rev[0]=1;
for(int i=1;i<=200000;i++)
{
jie[i]=jie[i-1]*i%mod;
rev[i]=quick_pow(jie[i]);
}
return;
}
int main()
{
int T,i,tk;
cin>>T;
init();
while(T--)
{
scanf("%d%d%d",&n,&m,&k);
ans=jie[k+m-1]*rev[m-1]%mod*rev[k]%mod;
for(i=1;i<=m;i++)
{
tk=k-1ll*i*n;
if(tk<0) break;
if(i&1) ans=((ans-jie[m]*rev[i]%mod*rev[m-i]%mod*jie[tk+m-1]%mod*rev[m-1]%mod*rev[tk]%mod)%mod+mod)%mod;
else ans=(ans+jie[m]*rev[i]%mod*rev[m-i]%mod*jie[tk+m-1]%mod*rev[m-1]%mod*rev[tk]%mod)%mod;
}
printf("%I64d\n",ans);
}
return 0;
}