「CF1437F」Emotional Fishermen 题解

小水题一道

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_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;
}
posted @ 2025-01-22 15:26  cqbzljh  阅读(34)  评论(0)    收藏  举报