题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6397
题意:共有m个取值范围为[0,n-1]的数字,求使得总和为k的方案数。
思路:链接:https://blog.csdn.net/yu121380/article/details/82802502
我们可以把k看成k个1,通过m-1个隔板来分割成m个数字。但是这样做会有问题,就是数字可能为0,但是隔板法不允许这种情况存在,所以我们可以做一个等价处理,即将取值范围+1,即[1,n],那么相应的总和也要加上m,即k+m,则问题转化为 “共有m个取值范围为[1,n]的数字,求使得总和为m+k的方案数”, 根据隔板法可以得出无限制的情况下方案数为 C(m+k-1, m-1)。
对于此题,共有ans=C(k+m-1,m),但此时,会出现有的数>=n,所以我们要将减掉 出现1数值>=n,(有C(m,1)种选法)2个数值>=n(有C(m,2)种选法).....(k/n,m)个数值大于等于n的情况 ,f(i)=C(k+m-n*i-1,m)....但减去f(1)时,会多减了f(2),f(3)......,所以要加上f(2),但此时又多加了f(3)....如此往复,发现,当i为奇数时,减去f(i),i为偶数时,加上f(i)
这道题的k,就相当于有k个小球,放到m个盒子里,如果不考虑Xi的约束条件,答案就是。我们考虑,这些答案里会有某些,我们应该把这些情况去掉。当有一个的时候,有种Xi。此时就相当于k个小球中,已经有n个小球放到了某个盒子里,接下来把剩下的k-n个小球放到m个盒子里就是有这么多种情况。所以我们用,这样的话,多减去了有两个的情况,我们又要加回来。考虑到这里,就不难发现,这可以用容斥原理解决。
#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <map>
#include <set>
#include <bitset>
#include <stack>
#define ull unsigned long long
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define mems(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const ll mod=998244353;
const int N=2e5+10;
const double pi=acos(-1);
const int inf=0x3f3f3f3f;
const int M=50000+5;
ll n,m,k;
ll f[N],inv[N];
ll qpow(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1)
ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans%mod;
}
void init()
{
f[0]=inv[0]=1;
for(int i=1;i<N;i++)
{
f[i]=f[i-1]*i%mod;
inv[i]=qpow(f[i],mod-2);
}
}
ll CC(ll n,ll m)
{
return f[n]*inv[n-m]%mod*inv[m]%mod;
}
int main()
{
init();
int t;
scanf("%d",&t);
while(t--)
{
scanf("%lld%lld%lld",&n,&m,&k);
ll ans=CC(k+m-1,m-1);
ll len=min(k/n,m);
for(int i=1;i<=len;i++)
{
if(i&1)
ans=(ans-CC(m,i)*CC(k+m-1-i*n,m-1)%mod+mod)%mod;
else
ans=(ans+CC(m,i)*CC(k+m-1-i*n,m-1)%mod)%mod;
}
printf("%lld\n",ans%mod);
}
}