2019牛客暑期多校训练营(第七场) I Chessboard

传送门

题意:给你一个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;
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值