B题题解:

题目解析:

这道题本质上是一个组合数学问题。我们需要计算将编号为 1 到 n 的球放入左右两个盒子(左盒 x 个,右盒 n−x个)的方案数,且满足相邻球在不同盒子的“断点”数量恰好为 t。我们需要分情况讨论,核心在于如何将 xx 个球(假设为类型 A)和 n−x 个球(假设为类型 B)分配到 t+1 个段中。

组合数学推导

假设我们要把 𝑥 个 A 球分成 𝑖 段,把 𝑛−𝑥 个 B 球分成 𝑗 段。

情况一:A 球在奇数段(即第一段是 A) 那么 A 球的段数 𝑖 应该是 ⌈t+1⌉ 。 B 球的段数 𝑗 应该是 ⌊t+1⌋ 。

情况二:B 球在奇数段(即第一段是 B) 那么 B 球的段数 𝑖 应该是 ⌈t+1⌉ 。 A 球的段数 𝑗 应该是 ⌊t+1⌋ 。

要把 𝑚 个相同的球分成 𝑟 个非空的组,方案数是 𝐶(𝑚−1,𝑟−1) 。

答案 = 𝐶(𝑥−1,𝑖−1)×𝐶(𝑛−𝑥−1,𝑗−1)+𝐶(𝑥−1,𝑗−1)×𝐶(𝑛−𝑥−1,𝑖−1) 其中 𝑖=⌈(𝑡+1)/2⌉,𝑗=⌊(𝑡+1)/2⌋ 。

注意边界条件: 如果要求的段数大于球数(即 𝑖>𝑥 或 𝑗>𝑛−𝑥 ),说明无法分出这么多段,该情况方案数为 0。

代码演示:

#include<bits/stdc++.h>
using namespace std;
#define int long long 
#define endl '\n'
const int N = 1000005;
const int mod = 998244353;

int fz[N],fm[N];
//fz[i]存储i!,fm[i]存储inv_i!mod p(阶乘逆元的模结果)
//利用快速幂计算逆元函数
int fpow(int a,int b){
	int r=1;
	a%=mod;
	while(b){
		if(b&1){
			r=r*a%mod;
		}
		a=a*a%mod;
		b>>=1;
	}
	return r;
}
//数组定义及初始化
void init(){
	fz[0]=fm[0]=1;
	for(int i=1;i<=1000000;i++){
		fz[i]=fz[i-1]*i%mod;
	}
	fm[1000000]=fpow(fz[1000000],mod-2);//根据费马小定理;
	for(int i=999999;i>0;i--){
		fm[i]=fm[i+1]*(i+1)%mod;
	}
}
//查询组合数函数,时间复杂度为O(1)
int f1(int n,int k){
	if(n<k) return 0;
	return fz[n]*fm[k]%mod*fm[n-k]%mod;
}

int C(int m,int r){
	if(r==0){
		if(m==0){
			return 1;
		}else return 0;
	}
	if(r>m) return 0;
	return f1(m-1,r-1);
}

void solve(){
	int n,x,t;
	cin>>n>>x>>t;
	int m1=ceil((t+1)*1.0/2);
	int m2=(t+1)/2;
	if(t+1>n){
		cout<<"0"<<endl;
		return;
	}
	cout<<(C(x,m1)*C(n-x,m2)%mod+C(x,m2)*C(n-x,m1)%mod)%mod<<endl;
}

signed main(){
	ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
	int T=1;cin>>T;
	init();
	while(T--){
		solve();
	}
	return 0;
}