CodeForces1312D 组合数
题意
找出满足下列条件的数组个数:
- 包含 n 个元素
- 每个元素的数值范围在 1 到 m 之间
- 数组中恰好只有一对元素的数值相等
- 数组中存在一个下标 i 满足在 i 之前数组是严格递增的,而在 i 之后数组是严格递减的 (若 j < i 则 aj < aj + 1,若 j ≥ i 则 aj > aj + 1)。
题解
显然是一个组合数的题,首先考虑从m个数字中取出n - 1个不同的数字 C(m,n - 1),然后从这个n - 1个数字中选取一个作为重复元素(不能是当中的最大值),有n - 2中情况,剩下的非顶点以及非重复元素的数字分为在左侧和在右侧两种可能,即2 ^ (n - 3)
因此推出来的公式就是C(n - 1, m) * (n - 2) * (2 ^ (n - 3)), 对于n == 2的场景,特判为0即可
代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define fi first
#define se second
#define PII pair<int,int>
#define PLL pair<long long,long long>
#define mp make_pair
const int maxn = 2e5 + 10;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
int N,M,K;
int F[maxn],Finv[maxn],inv[maxn];
void init() {
inv[1] = 1;
for(int i = 2; i < maxn ; i ++) {
inv[i] = (mod - mod / i) * 1ll * inv[mod % i] % mod;
}
F[0] = Finv[0] = 1;
for(int i = 1; i < maxn; i ++) {
F[i] = F[i - 1] * 1ll * i % mod;
Finv[i] = Finv[i - 1] * 1ll * inv[i] % mod;
}
}
LL C(int n,int m) { // C(n,m)
if(m < 0 || m > n) return 0;
return F[n] * 1ll * Finv[n - m] % mod * Finv[m] % mod;
}
LL q_p(LL a,LL b) {
LL ans = 1;
while(b) {
if(b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
int main(){
LL n,m; init();
scanf("%lld%lld",&n,&m);
if(n == 2) {
cout << 0 << endl;
return 0;
}
LL ans = C(m,n - 1) * (n - 2) % mod * q_p(2,n - 3) % mod;
cout << ans << endl;
return 0;
}