Loading

【题解】CF1437F Emotional Fishermen

提供一个不用组合数的方法。

首先对 \(a_i\) 从小到大排序。

我们定义状态 \(f_{i,j}\) 表示当前最大值为 \(a_i\),排列 \(p\) 填了前面 \(j\) 个方案数。

那么有初值 \(f_{0,0}=1\)

依题意,我们有两种转移。

第一种是在排列后面加入一个高兴的人,枚举 \(k\) 使得 \(a_k\ge 2a_i\),有 \(f_{i,j}\to f_{k,j+1}\)

第二种是加入一个难过的人,我们找到最大的 \(k\) 使得 \(2a_k\le a_i\),那么有 \(f_{i,j-1}\to f_{i,j}\)。考虑填入的是哪个人,我们一共有 \(k\) 个人,然后有 \(j-1\) 个人固定了,其中有一个人是 \(i\) 不能算进去,所以在 \(k-(j-2)\) 个人种选一个,转移就是 \(f_{i,j}=(k-j+2)f_{i,j-1}\)

时间复杂度 \(\mathcal{O}(N^2)\)

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define N 5005
#define P 998244353
using namespace std;
int n,a[N],f[N][N],g[N][N];
int main(){
	scanf("%d",&n);
	rep(i,1,n)scanf("%d",&a[i]);
	sort(a+1,a+n+1);
	f[0][0] = g[0][0] = 1;
	rep(i,1,n)g[i][0] = 1;
	int pre = 0;
	rep(i,1,n){
		while(a[pre + 1] * 2 <= a[i])pre++;
		rep(j,1,pre + 1){
			f[i][j] = (1LL * (pre - j + 2) * f[i][j - 1] + f[i][j]) % P;
			f[i][j] = (f[i][j] + g[pre][j - 1]) % P;
			g[i][j] = (g[i - 1][j] + f[i][j]) % P;
		}
	}
	printf("%d\n",f[n][n]);
	return 0;
}
posted @ 2021-10-04 16:59  7KByte  阅读(31)  评论(0编辑  收藏  举报