P6561 [SBCOI2020] 人
考虑把 放在一起看,那么每组一共有三种情况:
- A: 选, 不选。
- B: 不选, 选。
- C:都不选。
且有一个限制,就是不允许相邻两个组别组成 BA 的形式,因为这样前一组的第二个和后一组的第一个成为了相邻的数,此时不符合题意。
所以我们把问题转化一下,就变成了:有多少种不出现 BA 形式的 A、B、C 组合?
设 A、B 情况分别有 个,那么 C 情况就有 个。
考虑放好 C 以后往相邻的两个 C 之间填 A、B,因为不能出现 BA 形式,所以只能把所有的 A 放在前面,把所有的 B 放在后面。也就是说,A、B 的数量确定时,方案数只有一个。
现在问题就变成了往相邻的两个 C 之间填 A、B 的方案数,由于放 A 与放 B 相互独立,所以可以使用乘法原理。
先考虑往 个 C 中填 个 A,一共 个空,每个空可以不填,考虑插板法:
- 的整数解有 组。
- 的整数解有 组。
解释:将原式转化为 ,再使用上面的结论即可。
所以对于 个空填 个,根据第二个结论,有 种答案。
同理对于 B,有 种答案。
最后根据乘法原理,答案数为 。
对于组合数的计算,发现模数要大于 且为质数,所以预处理阶乘与阶乘的逆元即可。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+5;
const int mod=998244353;
int T;
int m,a,b;
int inv[N],ninv[N];
int mi(int x,int y){
int res=1;
while(y){
if(y&1) (res*=x)%=mod;
y>>=1,(x*=x)%=mod;
}
return res;
}
int c(int x,int y){
return inv[x]*ninv[y]%mod*ninv[x-y]%mod;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>T;
inv[0]=ninv[0]=1;
for(int i=1;i<N;i++){
inv[i]=(i*inv[i-1])%mod;
ninv[i]=(mi(i,mod-2)*ninv[i-1])%mod;
}
while(T--){
cin>>m>>a>>b;
cout<<c(m-a,m-a-b)*c(m-b,m-a-b)%mod<<"\n";
}
return 0;
}

Comments NOTHING