题意:
m个位置每个位置可以填上[0,n-1]求m个数和为k的方案数
思路:
既然用生成函数做题的话先观察题目是否是求组合数,稍微思考发现题目求的就是组合数,于是开心的列一个生成函数(1+*x^1+x^2+...+x^n)
根据题目意思可以得到此题的指数型生成函数(1+x^1+x^2+...+x^(n-1))^m,表示每个位置可以放[0,n-1]共放置m个位置
对(1+x^1+x^2+...+x^(n-1))求和,根据等比数列求和公式得到(1-x^n)/(1-x),最终式子变成(1-x^n)^m*(1-x)^(-m)
对(1-x^n)^m二项式展开得到Σ(i=0->m)C(m,i)*(-1)^i*(x^n)^i,对(1-x)^(-m)进行泰勒展开处理得到Σ(i=0->无穷)C(m+i-1,i)x^i
泰勒展开:
因为x的最终表达式是x,所以可以得出a=1,所以f(a)==f'(a)==...==f(n)(a)==1,同时系数会因为求导和阶乘的缘故变为C(m+i-1,i),所以(1-x)^(-m)的泰勒展开结果为Σ(i=0->无穷)C(m+i-1,i)x^i
最终我们需要的是x^k前的系数就是答案了,至于怎么统计就看代码了
C++代码:
#include <bits/stdc++.h>
using namespace std;
const int mod = 998244353;
const int maxn = 200010;
int f[maxn],inv[maxn],n,m,k;
int C( int n , int m )
{
return 1LL*f[n]*inv[m]%mod*inv[n-m]%mod;
}
int Qpow( int a , int b )
{
int res = 1;
while ( b )
{
if ( b&1 )
res = 1LL*res*a%mod;
a = 1LL*a*a%mod;
b = b>>1;
}
return res;
}
int main()
{
f[0] = inv[0] = 1;
for ( int i = 1; i<maxn ; i++ )
{
f[i] = 1LL*f[i-1]*i%mod;
inv[i] = Qpow( f[i] , mod-2 );
}
for ( int T ; scanf ( "%d" , &T )==1 ; )
{
for ( int cas=1 ; cas<=T ; cas++ )
{
scanf ( "%d%d%d" , &n , &m , &k );
int ans = 0;
if ( 1LL*m*(n-1)<k )
{
printf ( "0\n" );
continue;
}
for ( int i=0 ; i<=k/n ; i++ )
{
int x = 1LL*C( m , i )*C( m+k-n*i-1 , m-1 )%mod;
if ( i%2==0 )
ans = ( ans+x )%mod;
else
ans = ( ans-x+mod )%mod;
}
printf ( "%d\n" , ans );
}
}
return 0;
}