CF-Round 83-Div. 2-D题
D. Count the Arrays
这道题就是问你有多少个满足要求的序列。跟上次一道题比较像。要求序列中存在一对相等的数,然后序列满足这样的要求,先是严格递增,然后严格递减。
然后问你存在多少个取模。
这道题是组合逆元问题。
还挺简单的把。。。(我没有膨胀。。)
我们这样考虑。因为存在一对相等的数字。所以有n-1个数字是不一样的,我们需要从m个数字中选择n-1个不一样的数字。组合问题把。。就是C(m, n-1)
然后这n-1个数字中选择一个数字进行重复。
这个地方我们 不能选择最大的数字,如果选择最大的数字的话。。那就不能进行严格递增然后严格递减的要求了。
所以我们有n-2个选择(排除最大的数字)
再考虑分布问题。题目没说最大的数字要在中间把。
所以最大数字的左边和右边是没有限制的。
我们考虑到这n个数字中有两个数字相同,必须摆放到最大数字的左边和右边。剩余还有n-3个数字。(这n-3个数字互不相同)每个数字有两种选择,选择左边或者右边。所以是2^(n-3)。
然后乘起来就是答案了。
C(m, n-1) (n-2) 2^(n-3)
注意每一步都要取模。
取模之后的数字可能发生变化不是原来的操作了。。
所以费马来啦。
这里的n可以达到2e5。所以乘法逆元
求组合数的时候也需要逆元。(原因上面我说过啦~)
代码部分:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 998244353;
const int N = 2e5 + 10;
int n, m;
ll fact[N];
void solve()
{
fact[0] = 1;
for (int i = 1; i < N; i++)
{
fact[i] = fact[i - 1] * i % mod;
}
}
ll npower(ll a, ll b)
{
ll res = 1;
while (b)
{
if (b & 1)
{
res = res * a % mod;
}
a = a * a % mod;
b >>= 1;
}
return res;
}
ll C(int a, int b)
{
ll res1 = fact[b] * fact[a - b] % mod;
res1 = npower(res1, mod - 2);
return fact[a] * res1 % mod;
}
int main()
{
solve();
cin >> n >> m;
ll ans = 0;
if (n > 2)
{
ll ans1 = npower(2, n - 3) % mod;
ll ans2 = C(m, n - 1);
ans = (ans1 * ans2 % mod) * (n - 2) % mod;
}
cout << ans << endl;
return 0;
}