CF1153F Serval and Bonus Problem

CF1153F Serval and Bonus Problem


其实这个题很呆,但是考场上沙雕了,看见实数,期望什么的样例还积分,不会就溜了

大致题意:

有一段长为\(l\)的线段,有\(n\)个区间,左右端点在\([0,l)\)间均匀随机(可能不是整数)

求期望被至少\(k\)段区间覆盖的长度,对998244353取膜

其实这个模型很呆,但像我这么sb的第一次看见(可能是忘了)就不会

因为是范围内的实数,那么可以认为没有重合,那么这条线段会被\(2n\)个端点分成\(2n+1\)段,因为端点也是随机的,所以每一段期望长度都相同,都是\(\frac{l}{2n+1}\)

所以只要对于每一段,计算这一段被至少\(k\)段区间覆盖的概率

既然算概率当然直接算方案数了,直接dp,设\(f[i][j]\)表示有\(i\)个端点,第\(i\)个端点后面的区间被\(j\)个线段覆盖的方案数。转移直接枚举\(i\)是一个区间的开始还是结束,如果是结束还要乘\(j\)转移,表示这个端点可以匹配前面\(j\)个的任意一个

最后直接枚举合法的方案就行了,记住这个算的是方案数,还要除以\(f[2n][0]\)才是概率。

#include<bits/stdc++.h>
#define il inline
#define vd void
#define mod 998244353
typedef long long ll;
il ll gi(){
	ll x=0,f=1;
	char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
	return x*f;
}
il int pow(int x,int y){
	int ret=1;
	while(y){
		if(y&1)ret=1ll*ret*x%mod;
		x=1ll*x*x%mod;y>>=1;
	}
	return ret;
}
int f[4010][2010],p[2010];
int main(){
#ifdef XZZSB
	freopen("in.in","r",stdin);
	freopen("out.out","w",stdout);
#endif
	int n=gi(),k=gi(),l=1ll*gi()*pow(n<<1|1,mod-2)%mod;
	p[0]=1;for(int i=1;i<=n;++i)p[i]=1ll*i*p[i-1]%mod;
	f[0][0]=1;
	for(int i=0;i<n<<1;++i){
		for(int j=std::min(n,i);~j;--j){
			f[i+1][j+1]=(f[i+1][j+1]+f[i][j])%mod;
			if(j)f[i+1][j-1]=(f[i+1][j-1]+1ll*f[i][j]*j)%mod;
		}
	}
	int ans=0;
	for(int i=1;i<=n<<1;++i)
		for(int j=k;j<=n;++j)
			ans=(ans+1ll*f[i][j]*f[(n<<1)-i][j]%mod*p[j])%mod;
	printf("%lld\n",1ll*ans*l%mod*pow(f[n<<1][0],mod-2)%mod);
	return 0;
}
posted @ 2019-04-14 20:12  菜狗xzz  阅读(487)  评论(0编辑  收藏  举报