题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6397
题目大意:T组测试数据,输入n,m,k表示,选m个数,sum(mi)=k的情况有多少种,其中mi>=0&&mi<n。
思路:多谢猛哥给我讲题,用到的(排列组合+容斥).
我们可以将题目看成选k个1,然后将它放在m个盒子中,每个盒子就是一个mi,然后这m个盒子就相当于m个数字。
现在提取第一个知识点:1.k个小球放在m个盒子中,有多少种放法。(可是使用隔板法)。
由于mi还可以为0,那么也就是说盒子中可以不放小球。现在就变成了k个小球放在m个盒子中,有多少种放法,盒子中可以不放小球。(我们可以添加一些权值为0的小球,然后进行求其组合数,利用隔板法)。
以上我们得到了m个数之和组成k的情况有多少种,由于mi<n所以我们要讲mi>=n的情况减去,
考虑mi>=n情况的数量:只有1个,2个,3个....。很明显有两个mi>=n的情况包含了有一个mi>=n的情况。。以此类推,就是容斥了。
用小球表示就是一个盒子中放权值为1的小球数量>=n。由于总共只有k个权值1的小球,因此我们只用考虑i<=int(k/n)个情况就好了。
由于暴力组合数比较慢,我们可以打一个表,进行预处理。
ACCode:
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define Pair pair<int,int>
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// ??
//std::ios::sync_with_stdio(false);
// register
const int MAXN=1e6+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll mod=998244353;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
ll Inv[MAXN],Finv[MAXN],F[MAXN];
int n,m,k;
void Intt(){
Inv[1]=1;
for(int i=2;i<MAXN;++i){
Inv[i]=(1ll*(mod-mod/i)*Inv[mod%i])%mod;
}
F[0]=Finv[0]=1;
for(int i=1;i<MAXN;++i){
F[i]=1ll*F[i-1]*i%mod;
Finv[i]=1ll*Finv[i-1]*Inv[i]%mod;
}
}
ll Comb(ll a,ll b){//C(a,b)a个里面选b个
if(b<0||b>a||a<0) return 0;
return 1ll*(F[a]*Finv[a-b]%mod)*Finv[b]%mod;
}
int main(){
Intt();
int T;scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&m,&k);
ll ans=Comb(k+m-1,m-1);
// printf("%lld\n",ans);
for(int i=1;i*n<=k;++i){
if(i%2) ans=(ans-1ll*Comb(m,i)*Comb(k+m-1-i*n,m-1)%mod+mod)%mod;
else ans=(ans+1ll*Comb(m,i)*Comb(k+m-1-i*n,m-1))%mod;
}printf("%lld\n",ans);
}
}