首页 > 其他分享 >「CF1437F」Emotional Fishermen 题解

「CF1437F」Emotional Fishermen 题解

时间:2025-01-22 15:31:36浏览次数:1  
标签:const int 题解 Module return using Fishermen Emotional dp

小水题一道

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;
}

标签:const,int,题解,Module,return,using,Fishermen,Emotional,dp
From: https://www.cnblogs.com/cqbzljh/p/18686174

相关文章

  • 「CF618F」Double Knapsack 题解
    只能说。。。Description给你两个可重集 \(A,B\),\(A,B\) 的元素个数都为 \(n\),它们中每个元素的大小 \(x\in[1,n]\)。请你分别找出 \(A,B\) 的子集,使得它们中的元素之和相等。\(n\leq10^6\)。Solution将找子集强化成找子段(不知道怎么想的),令\(sa_{n}\)表示\(A\)......
  • 「CF1854D」Michael and Hotel 题解
    逆天交互题、、、我只能说阈值分治赛高!!!Description有一个有 \(n\) 个点的内向基环树森林,zlsim位于 \(1\) 号节点,请你通过以下操作求出哪些节点(包括 )可以通过从这两点开始沿边行走若干步汇至一点。给出两个参数 \(u,k\) 和点集 \(S\),询问是否能够通过从 \(u\) 出......
  • P9678 题解
    题意给定一棵\(n\)个点的树\(T\),边有边权。现在有\(q\)组询问,每组询问给出\(l,r\),求出:\[\min_{l\lei<j\ler}\operatorname{dist}(i,j)\]\(n\le2\times10^5\),\(q\le10^6\),\(1\lew\le10^9\)。由于与路径长度有关,所以考虑点分治或者LCA。由于笔......
  • ZJOI2010 基站选址 题解
    ZJOI2010基站选址题解题目链接dp+线段树优化。暴力dp状态设计:自然想到设\(f(i,j)\)表示只考虑前\(i\)个村庄,在前\(i\)个村庄中建\(j\)个基站,并且在第\(i\)个存在建立基站时,最小的费用。转移:转移时,枚举上一个建基站的村庄\(p\)(这同时告诉我们,\(j=1\)......
  • P1048 [NOIP2005 普及组] 采药 题解
    原题链接题目大意:采药,每种药只有一株,每株有它的价值和采它所需的时间,现时间有限,请你输出在有限时间内能获得的价值最大是多少。分析:1.这是一个典型的01背包问题(DP)01背包问题的典型特征:有一个限定容量的背包(对应本题中的时间),有物品(每种只有一个)(对应本题中的药株),物品有......
  • 洛谷P1002 [NOIP2002 普及组] 过河卒 题解
    原题链接题目大意:棋盘上A点有一个过河卒,需要走到目标B点。卒行走的规则:向下或向右。同时在棋盘上C点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。棋盘用坐标表示,AA点(0,0)、BB点(n,m),同样马的位置坐标是需要给出的。现在要求你计算出......
  • 2025牛客寒假算法基础集训营1 ptlks的题解
    A.茕茕孑立之影题意:给定序列,找出一个数x,满足x和数组中任意一个元素都互不为倍数关系思路x范围为1e18以内,序列元素范围为1e9以内,选大于1e9的质数即可,特判序列中有1的情况。代码点击查看代码voidsolve(){ intn; cin>>n; intf=1; for(inti=1;i<=n;i++){ cin>>a[......
  • 题解:洛谷 P4879 ycz的妹子
    题目https://www.luogu.com.cn/problem/P4879感觉还比较简单的线段树。首先我们先建立一棵线段树(范围:)。voidbuild(intk,intl,intr){ tr[k]={l,r}; if(l==r){ Tree[k]=a[l],c[k]=(l<=n); return; } intmid=(l+r)>>1ll; build(k<<1ll,l,mid); build((k<<1ll)|1l......
  • 题解:洛谷 P1351 [NOIP2014 提高组] 联合权值
    题目https://www.luogu.com.cn/problem/P1351我们可以发现,若点对  的距离为 ,则它们一定会经过一个中转点,因此我们考虑枚举中转点 ,然后枚举与  有直接边连接的两个点,按照题意统计答案即可。#include<bits/stdc++.h>usingnamespacestd;#pragmaG++optimisze(3,"Ofas......
  • 【题解】Luogu P4340 [SHOI2016] 随机序列
    简单手摸后发现,答案就是这么一个式子:\[(3^{n-1}-3^{n-2})a_1+(3^{n-2}-3^{n-3})a_1a_2+\dots+(3^1-3^0)a_1a_2\dotsa_{n-1}+a_1a_2\dotsa_n\]啊当然证明也是好证的,对于\(a_1\)这一项,它后面放+或-都会对系数加一,而放*不会影响系数,因此系数就是总数的三分之二。其它前缀......