小水题一道
Description
有 n\((n\le 5000)\) 个渔民,每个渔民钓了一条重 \(a_i\) 的鱼,渔民按任意顺序展示他们的鱼。
若当前渔民的鱼的重量为\(x\),之前展示过的鱼的最大重量 \(y\)。
一个排列满足条件当且仅当对于每个 \(x\),满足 \(2y\le x\) 或 \(2x\le y\)。
问有多少个排列满足条件,对 \(998244353\) 取模。
Solution
我们如果将每一个曾作为最大重量的鱼看作关键点,那么对于某一种关键点取法,向里面填数是容易计数的。只需要考虑怎样定义状态方便转移即可。
首先,我们将鱼的重量排序,然后定义 \(dp_{i}\) 表示第 \(i\) 条鱼关键点的方案数。显然有初值 \(dp_{n}=1\)。又定义 \(p_{i}\) 表示最大的满足 \(2a_{i-p_{i}}>a_{i}\) 的数,则有以下转移:
\[dp_{i}=\sum_{a_{j}\geq 2a_{i}}{dp_{j}\times \prod_{k=1}^{p_{j}}(n-j-1+k)\times \prod_{k=p_{j}+1}^{j-i+1}(n-j+k)}
\]
最后同理处理答案即可。
Code
#include <bits/stdc++.h>
using namespace std;using ci = const int;using u32 = uint32_t;
using i64 = int64_t;
using u64 = uint64_t;template<class T> inline void Max(T &x, const T &y) { if (x < y) x = y; }
template<class T> inline void Min(T &x, const T &y) { if (y < x) x = y; }const int N = 5005;
const int mod = 998244353;constexpr int dil(int x) { return x >> 31 ? x + mod : x; }struct Module {using cm = const Module;int v;Module() {}Module(int _v) : v(_v) {}#define _(s) friend Module operator s(cm &x, cm &y)_(+) { return dil(x.v + y.v - mod); }_(-) { return dil(x.v - y.v); }_(*) { return u64(x.v) * y.v % mod; }
#undef _#define _(s) void operator s##=(cm &o) { *this = *this s o; }_(+) _(-) _(*)
#undef _
};Module qpow(Module x, int y) {Module z(1);do if (y & 1) z *= x;while (x *= x, y >>= 1);return z;
}int n, a[N];
Module dp[N], fct[N], ifct[N];void init(ci n) {fct[0] = 1;for (int i = 1; i <= n; ++i)fct[i] = fct[i - 1] * i;ifct[n] = qpow(fct[n], mod - 2);for (int i = n; i; --i)ifct[i - 1] = ifct[i] * i;
}inline Module mul(int l, int r) {if (!l) return (r == -1);return fct[r] * ifct[l - 1];
}int P[N];int main() {
#ifndef ONLINE_JUDGEfreopen(".in", "r", stdin);freopen(".out", "w", stdout);
#endifios_base::sync_with_stdio(0);cin.tie(0); cout.tie(0);cin >> n;init(n);for (int i = 1; i <= n; ++i) cin >> a[i];sort(a + 1, a + 1 + n);for (int i = 1; i <= n; ++i) {int &p = P[i];while (2 * a[i - p] > a[i]) ++p; --p;}dp[n] = 1;for (int i = n - 1; i; --i) {for (int j = i + 1; j <= n; ++j) {if (a[j] >= 2 * a[i]) {int p = P[j];dp[i] += dp[j] * mul(n - j, n - j + p - 1) * mul(n - j + p + 1, n - i - 1);}}}Module ans(0);for (int i = 1; i <= n; ++i) {int p = P[i];ans += dp[i] * mul(n - i, n - i - 1 + p) * mul(n - i + p + 1, n - 1);}cout << ans.v;return 0;
}