https://codeforces.com/contest/1569/problem/C
题意:
n个数,每经过一个数它就-1,如果当所有数减完的时候没有一个数连续减了两次那这样一个序列就叫好序列,求所有好序列的数量,答案mod998244353
题解:
我们可以发现不管n是多少,到最后我们都只用看只剩下最后两个数的情况,而剩下的两个数肯定是最大数和次大数.
所以我们可以分以下三种情况讨论:
1.最大数=次大数
和位置无关,所有排列的序列都是好序列,答案为n!
2.最大数>=次大数+2
所有序列都不是好序列,答案为0
3.最大数只有一个,且次大数和最大数的差值为1
我们通过观察可以发现,至少有一个次大数要在最大数的右边才是好序列,那么答案可以为全排列减去次大数全都在最大数左边的情况.
次大数圈都在最大数左边的方案数可以通过枚举最大数的位置来计算:
我们设有cnt个次大数,那么最大数就可以放在n~cnt+1的位置上.设最大数的位置为i,最大数左边的空位就是i-1个,右边的空位就是n- i个,次大数只能放在左边的位置,所以有$\binom{cnt}{i-1}$种放法,现在已经放了cnt个次大数和一个最大数,所以还剩下n-cnt-1个数,剩下的数可以随意放所以就是$(n-cnt-1)!$放法.
$(n-cnt-1)!*\binom{cnt}{i-1}$就是最大数放在第i个位置时不合法的方案数,枚举i从n~cnt+1,依次减掉即可.
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
| #include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<vector> #include<queue> #include<stack> #include<map> #include<unordered_map> #include<set>
#pragma GCC optimize(2) using namespace std; #define ll long long #define PII pair<int,int> #define PLL pair<ll,ll> #define fi first #define se second #define pb push_back #define debug(a) cout << #a << " " << a << '\n'; const int N = 2e5 + 5; const int M = 1e5 + 5; const int INF = 0x3f3f3f3f; const ll LLINF = 0x3f3f3f3f3f3f3f3f; const ll mod = 998244353;
inline ll read();
ll qpow(ll a, ll b) { ll res = 1; while (b) { if (b & 1)res = res * a % mod; a = (a * a) % mod; b >>= 1; } return res; }
int n, m, t; ll a[N]; ll pre[N]; ll A(ll nn, ll mm) { return pre[nn] * qpow(pre[nn - mm], mod - 2) % mod; }
void solve() { cin >> n; ll maxx = -1;
for (int i = 0; i < n; i++) { cin >> a[i]; } sort(a, a + n); if (a[n - 1] >= a[n - 2] + 2)cout << 0 << '\n'; else if (a[n - 1] == a[n - 2])cout << pre[n] << '\n'; else { int cnt = 0; for (int i = 0; i < n; i++) { if (a[i] == a[n - 2])cnt++; } ll ans = pre[n]; for (int i = n; i >= cnt + 1; i--) { ll res = (A(i - 1, cnt) * pre[n - cnt - 1]) % mod; ans = (ans - res + mod) % mod; } cout << ans % mod << '\n';
}
}
int main() { t = read(); pre[0] = 1;
for (int i = 1; i <= 2e5; i++) { pre[i] = (pre[i - 1] * i) % mod; } while (t--) { solve(); }
return 0; }
inline ll read() { char ch = getchar(); ll p = 1, data = 0; while (ch < '0' || ch > '9') { if (ch == '-')p = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { data = data * 10 + (ch ^ 48); ch = getchar(); } return p * data; }
|