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;
}

京公网安备 11010502036488号