题目链接: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);
	}
}