Pro:
https://www.luogu.com.cn/problem/CF1437F
有n个渔民,每个渔民钓了一条重(a_i)的鱼
渔民按任意顺序展示他们的鱼。
若当前渔民的鱼的重量为(x),之前展示过的鱼的最大重量(y)
一个排列满足条件当且仅当对于每个(x),满足(2y≤x)或(2x≤y)
问有多少个排列满足条件,对(998244353)取模
(n<=1e5)
Sol:
这个题的核心想法是dp时每次枚举转移下一个happy的渔夫
也就是使得当前max变化的渔夫
把所有数字从小到大排好序后
按照刚才提到的那个想法转移
发现任意两个happy的渔夫之间
一定都是sad的渔夫
考虑把它们放在什么位置
从dp的想法来考虑的话可以再记一维当前有多少个sad的渔夫还没有决定位置
每当放了一个happy的渔夫后考虑在他后面放多少个sad的渔夫
这样状态(O(n^2)) 转移(O(n)) 总共(O(n^3))
考虑在枚举下一个happy的渔夫的时候直接给中间的sad的渔夫分配位置
这个的方案数就是一个n选m排列的形式
转移的时候直接乘上就可以了
经过推导
可以得到这样一个式子
[
fi=sum_{j=1}^{cnt_i} f_j * frac{(n-2-cnt_j)!}{(n-1-cnt_i)!}
]
直接暴力dp这个式子的复杂度是(O(n^2))的
做一些简单的数学变化加上前缀和优化即可变为(O(n))
#include<bits/stdc++.h>
#define N 220000
#define db double
#define ll long long
#define ldb long double
#define ull unsigned long long
using namespace std;
const int h=3,ki=149,mo=998244353;
int mod(int x){return (x%mo+mo)%mo;}
int inc(int x,int k){x+=k;return x<mo?x:x-mo;}
int dec(int x,int k){x-=k;return x>=0?x:x+mo;}
int ksm(int x,int k)
{
int ans=1;
while(k){if(k&1)ans=1ll*ans*x%mo;k>>=1;x=1ll*x*x%mo;}
return ans;
}
int inv(int x){return ksm(mod(x),mo-2);}
int read()
{
char ch=0;int x=0,flag=1;
while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0',ch=getchar();}
return x*flag;
}
void write(int x)
{
if(!x)return (void)putchar(48);
if(x<0)putchar(45),x=-x;
int len=0,p[20];
while(x)p[++len]=x%10,x/=10;
for(int i=len;i>=1;i--)putchar(p[i]+48);
}
const db eps=1e-7,inf=1e9+7,pi=acos(-1);
db Read(){db x;scanf("%lf",&x);return x;}
void Write(db x){printf("%lf",x);}
int fac[N],vac[N];
void prepare(int n)
{
fac[0]=1;for(int i=1;i<=n;i++)fac[i]=1ll*fac[i-1]*i%mo;
vac[n]=inv(fac[n]);for(int i=n;i>=1;i--)vac[i-1]=1ll*vac[i]*i%mo;
}
int a[N],f[N],s[N],dp[N];
int main()
{
int n=read();
for(int i=1;i<=n;i++)a[i]=read();sort(a+1,a+n+1);
for(int i=1,j=0;i<=n;i++){while(j!=n&&2*a[j+1]<=a[i])j++;f[i]=j;}
if(f[n]!=n-1){printf("0");return 0;}prepare(n);
for(int i=1;i<=n;i++)
{
dp[i]=inc(1ll*fac[n-1]*vac[n-1-f[i]]%mo,1ll*vac[n-1-f[i]]*s[f[i]]%mo);
s[i]=inc(s[i-1],(n-2-f[i]>=0)?1ll*fac[n-2-f[i]]*dp[i]%mo:0);
}
write(dp[n]);
return 0;
}