【XSY3395】逃亡(概率与期望,组合数)

首先 “被经过的整点的期望个数” 不好求,我们可以把它看成 “每个整点被经过的概率的和”。

对于某个整点,求 “它被任意一个人经过的概率” 不好求,我们可以求 “它不被任意一个人经过的概率”,那么现在的问题是求某个整点不被某个人经过的概率,或者说求某个整点被某个人经过的概率。

把这个人看作原点,然后设这个整点的坐标为 i i i(不妨设 i ≥ 0 i\geq 0 i0 i < 0 i<0 i<0 同理)。考虑转化到坐标-时间图像上,现在问题转化为:从原点开始走,每一步能往右上/右下走,求走 n n n 步,过程中碰到直线 y = i y=i y=i 的走法方案数,最后除个 2 n 2^n 2n 即为概率。

在这里插入图片描述

(本文所有图片均引用自题解的 PPT)

类似卡特兰数,我们考虑翻折:对于一条碰到 y = i y=i y=i 且终点 j < i j<i j<i 的折线,我们找到它第一次碰到 y = i y=i y=i 的位置,并把这条折线在这个位置之后的所有部分都沿 y = i y=i y=i 做翻折,那么就得到了一条终点在 j ′ > i j'>i j>i 的折线:

在这里插入图片描述

而且显然任意一条终点在 j ′ > i j'>i j>i 的折线,都唯一对应着一条终点在 j ′ j' j 的折线(它自己),以及一条终点在 j j j 的折线(上述翻折过程的逆过程得到的折线)。

那么如果设 E ( i ) E(i) E(i) 表示终点在 i i i 的走法方案数,那么碰到直线 y = i y=i y=i 的走法方案数即为:
E ( i ) + 2 ∑ j > i E ( j ) E(i)+2\sum_{j>i} E(j) E(i)+2j>iE(j)
E ( i ) E(i) E(i) 也比较好求:容易得到终点在 i i i 需要向上走 n + i 2 \frac{n+i}{2} 2n+i 步,于是 E ( i ) = [ n ≡ i ( m o d 2 ) ] ( n n + i 2 ) E(i)=[n\equiv i\pmod 2]\dbinom{n}{\frac{n+i}{2}} E(i)=[ni(mod2)](2n+in)

那么我们直接枚举每一个可能经过的整点( O ( n m ) O(nm) O(nm) 个),再对枚举的整点枚举每一个人,时间复杂度 O ( n m 2 ) O(nm^2) O(nm2)

#include<bits/stdc++.h>

#define M 25
#define N 12000010
#define fi first
#define se second
#define pii pair<int,int>
#define mk(a,b) make_pair(a,b)
#define INF 0x7fffffff

using namespace std;

namespace modular
{
	const int mod=998244353;
	inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
	inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
	inline int mul(int x,int y){return 1ll*x*y%mod;}
}using namespace modular;

inline int poww(int a,int b)
{
	int ans=1;
	while(b)
	{
		if(b&1) ans=mul(ans,a);
		a=mul(a,a);
		b>>=1;
	}
	return ans;
}

inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^'0');
		ch=getchar();
	}
	return x*f;
}

int n,m,x[M];
int fac[N],ifac[N],E[N];

vector<pii>part;

int C(int n,int m)
{
	return mul(mul(fac[n],ifac[m]),ifac[n-m]);
}

int calc(int now)
{
	int p=1;
	for(int i=1;i<=m;i++)
		if(abs(now-x[i])<=n)
			p=mul(p,dec(1,E[abs(now-x[i])]));
	return dec(1,p);
}

int main()
{
	n=read(),m=read();
	int inv=poww(poww(2,n),mod-2);
	fac[0]=1;
	for(int i=1;i<=n;i++) fac[i]=mul(fac[i-1],i);
	ifac[n]=poww(fac[n],mod-2);
	for(int i=n;i>=1;i--) ifac[i-1]=mul(ifac[i],i);
	int sum=0;
	for(int i=n;i>=0;i--)
	{
		int nowE=0;
		if(!((i&1)^(n&1))) nowE=mul(inv,C(n,(n+i)/2));
		E[i]=add(nowE,mul(sum,2));
		sum=add(sum,nowE);
	}
	for(int i=1;i<=m;i++)
	{
		x[i]=read();
		part.push_back(mk(x[i]-n,x[i]+n));
	}
	sort(part.begin(),part.end());
	int lstr=-INF,ans=0;
	for(pii now:part)
	{
		int l=now.fi,r=now.se;
		l=max(l,lstr+1);
		for(int i=l;i<=r;i++)
			ans=add(ans,calc(i));
		lstr=max(lstr,r);
	}
	printf("%d\n",ans);
	return 0;
}
/*
2 1
1
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值