小水题一道
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}\) 的数,则有以下转移:
最后同理处理答案即可。
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_JUDGE
freopen(".in", "r", stdin);
freopen(".out", "w", stdout);
#endif
ios_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;
}
标签:const,int,题解,Module,return,using,Fishermen,Emotional,dp
From: https://www.cnblogs.com/cqbzljh/p/18686174