【题解】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;
}