题意:给你一个N,M,然后你可以任意构造一个 k * k的矩阵,使得矩阵内每个元素最少是M,且任意不同行不同列的 k 个元素总和不超过N且都相同,问有多少种构造方法。
思路:
解释:我们枚举k,我们可以把每个元素减去M,那么就相当于N减去 k * M,简化问题并且不影响答案
解释:构造两个矩阵Ai,Bi 对于这两个矩阵,我们可知他们前面的系数和为T则满足结果 等价于 讲 T 分成2*k份(a,b都有k个)采用隔板法 (将T 转换成1排成一排,每两个1之间有一个隔间,那么k *2 + T有k * 2 - 1 +T个隔间,我们选择k * 2 - 1个隔间就可以把这些1分成k * 2份
解释:ai>=1 bi>=0 时 为啥可以写成c(T+k-1,2*k-1) ? 因为每个ai都>=1 所以我们将每个ai都减1 也就是总共减去了k。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 6000 + 10;
const int MOD = (int)998244353;
int F[N], Finv[N], inv[N];//F是阶乘,Finv是逆元的阶乘
void init(){
inv[1] = 1;
for(int i = 2; i < N; i ++){
inv[i] = (MOD - MOD / i) * 1ll * inv[MOD % i] % MOD;
}
F[0] = Finv[0] = 1;
for(int i = 1; i < N; i ++){
F[i] = F[i-1] * 1ll * i % MOD;
Finv[i] = Finv[i-1] * 1ll * inv[i] % MOD;
}
}
int comb(int n, int m){//comb(n, m)就是C(n, m) 从n中选择m个
if(m < 0 || m > n) return 0;
return F[n] * 1ll * Finv[n - m] % MOD * Finv[m] % MOD;
}
int main()
{
init();
int t;
cin>>t;
while(t--)
{
int n,m;
cin>>n>>m;
ll ans=0;
for(int k=1;k<=n;k++)
{
int T=n-k*m;
if(T<0)
break;
for(int j=0;j<=T;j++)
{
ans+=comb(j+2*k-1,2*k-1)%MOD;
ans=(ans-comb(j+k-1,2*k-1)+MOD)%MOD;
}
}
cout<<ans<<endl;
}
}