题解:P14639 【OIMO Round 1】世界线
Chasing_Meteors · · 题解
首先我们将作为前缀最大值的取出来,作为前缀最小值的取出来,如果都可以的,先不考虑。
则我们取出来的是一个单调不降序列和一个单调不升序列,将其中一个序列插入另一个序列中,方案数容易算出(经典
接着考虑都可以的数,这些数一定是一个前缀,有两个思路,第一种都可以的数有个性质,它们都是跟第一个数相同的数,且它们被限制一定要进入的某个序列一定都相同,所以枚举这个即可,最终容斥掉都可以的,都可以的一定是全部跟第一个相同的数都放在前面。这个是官解思路。
另一个思路是我的思路,枚举有多少个跟第一个数相同的数一定放入第一个序列,如果数量非零,那么它们一定要放入第一个比第一个数大的数的后面。数这个东西就好了。
:::info[code]
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using db = double;
using ldb = long double;
using lll = __int128;
using ulll = unsigned __int128;
#define int ll
#ifndef ONLINE_JUDGE
template <typename T>
void _debug(const T &t) { cerr << t << '\n'; }
template <typename T, typename... Args>
void _debug(const T &t, const Args &...rest)
{
cerr << t << ' ';
_debug(rest...);
}
#define debug(...) _debug(#__VA_ARGS__ " =", __VA_ARGS__)
#else
#define debug(...) 0
#endif
template <typename Iterator>
struct _Range
{
Iterator l, r;
friend ostream &operator<<(ostream &os, const _Range &t)
{
if (t.l >= t.r)
{
return os << "[]";
}
os << '[' << *t.l;
for (auto i = next(t.l); i != t.r; ++i)
{
os << ',' << *i;
}
return os << ']';
}
};
template <typename Container>
auto Range(const Container &c) -> _Range<decltype(begin(c))> { return {begin(c), end(c)}; }
template <typename T, size_t N>
auto Range(const T (&arr)[N]) -> _Range<const T *> { return {arr, arr + N}; }
template <typename Container>
auto Range(const Container &c, size_t l, size_t r) -> _Range<decltype(begin(c))>
{
auto start = begin(c) + min(l, c.size());
auto end = begin(c) + min(r, c.size());
return {start, end};
}
template <typename T, size_t N>
auto Range(const T (&arr)[N], size_t l, size_t r) -> _Range<const T *> { return {arr + min(l, N), arr + min(r, N)}; }
template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p) { return os << '(' << p.first << ',' << p.second << ')'; }
#define D debug
#define Rg Range
#define ifD(cond, ...) \
if (cond) \
{ \
debug(__VA_ARGS__); \
}
#undef int
const int N = 1e6 + 5, mod = 998244353;
int n, a[N];
ll res, fac[N], inv[N];
ll qpow(ll x, int k) {
ll res = 1;
while (k) {
if (k & 1) res = res * x % mod;
x = x * x % mod, k >>= 1;
}
return res;
}
ll C(int n, int m) {
return n >= m ? fac[n] * inv[m] % mod * inv[n - m] % mod : 0;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n;
fac[0] = 1;
for (int i = 1; i <= n; ++i) fac[i] = fac[i - 1] * i % mod;
inv[n] = qpow(fac[n], mod - 2);
for (int i = n; i; --i) inv[i - 1] = inv[i] * i % mod;
for (int i = 1; i <= n; ++i) cin >> a[i];
sort(a + 1, a + n + 1);
for (int i = 1, j = i; i <= n; ++i) {
// 有 n-j 个盒子,有 i-1 个球
j = i;
while (a[j + 1] == a[i]) ++j;
if (a[i] == a[i - 1]) res += C(i - 1 + n - j - 1, n - j - 1);
else res += C(n - 1, n - i);
}
cout << res % mod;
return 0;
}
:::