CF1437F Emotional Fishermen

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;
}
posted @ 2020-11-12 22:48  Creed-qwq  阅读(96)  评论(0编辑  收藏  举报