题目链接:CodeForces 1569C Jury Meeting
题目大意:
有\(n\)个人开会,每个人都有一些要说的任务,将这些人按一定顺序排列,使他们按顺序每人说一个自己的任务,如果一轮结束还有人有任务没说,则继续下一轮,说完所有任务的人直接跳过。
如果一个人连续说了两个任务,则这种排列不可行,求可行的排列数量。
题解:
很显然,会有一个人连续说两个任务说明在某一轮中他是最后一个发言的并且除他之外的其他人都已经说完了所有任务,因此在下一轮中他成为了第一个发言的人。
因此我们可以从所有人的任务数中的最大值的角度考虑这个问题。
阶乘可以通过预处理得到,由于要取模,所以计算\(\frac{1}{m+1}\)时需要求逆元,可以用费马小定理和快速幂求得。
#include <iostream>
#include <map>
using namespace std;
#define LL long long
const LL mod = 998244353;
 
LL fac[200010];
int t, n;
 
void init() {
    fac[0] = 1ll;
    for (int i = 1; i <= 200000; ++i) {
        fac[i] = (LL)i * fac[i - 1] % mod;
    }
}
 
LL qpow(LL x, LL k) {
    LL res = 1ll;
    while (k) {
        if (k & 1ll) res = res * x % mod;
        x = x * x % mod;
        k >>= 1;
    }
    return res;
}
 
int main() {
    init();
    scanf("%d", &t);
    while (t--) {
        map <int, int> mat;
        scanf("%d", &n);
        for (int i = 1, x; i <= n; ++i) {
            scanf("%d", &x);
            mat[x]++;
        }
        if (mat.rbegin()->second > 1) {
            cout << fac[n] << endl;
        } else if (mat.rbegin()->first - (++mat.rbegin())->first > 1) {
            cout << 0 << endl;
        } else {
            LL inv = qpow((++mat.rbegin())->second + 1ll, mod - 2ll);
            LL ans = (inv * (++mat.rbegin())->second % mod * fac[n]) % mod;
            cout << ans << endl;
        }
    }
    return 0;
}
原文:https://www.cnblogs.com/IzumiSagiri/p/15249580.html