逃亡

### Description

  数轴上有(m)个人,第(i)个人在(x_i),每一时刻每个人会等概率往左边或者右边移动一单位长度,求(n)秒之后期望有多少个点被经过,答案对(998244353)取模

  数据范围:反正就是(n*m^2)就好了(原来的那个范围给的太鬼畜了qwq)

  

Solution

  其实要求的就是每个点被经过的概率之和(因为每个点的贡献是(1)嘛)

  直接求不好下手,考虑对于每一个人(i)求出:点(x)没有被经过的概率,记为(P_i(x))

  这样最后统计的时候就不用考虑那么多了,点(x)被经过的概率就是(1-prodlimits_{i=1}^m P_i(x))

  现在每个人的影响就独立了,考虑对于一个人怎么求(P_i(x))

​  然后这个时候发现好像求(x)被经过的概率更加容易,所以我们转而求点(x)被第(i)个人经过的概率,(P_i(x))的话直接用(1)减一下就出来了

  按照(n)秒后这个人停下的位置(ed)分类,一个点(x)被经过有三种情况:(ed<x)(ed=x)(ed>x)

  首先考虑(x< ed)的情况,记(F(i))为这个人最后在(i)处停下的概率,那么这部分的结果为(sumlimits_{i=x+1}^{+infty}F(i))(然而实际上当(i)与起点的距离大于(n)的时候(F(i)=0),所以只用计算到起点(+n)的位置就好了)

  然后看(ed<x)的情况,这部分看起来比较麻烦,因为我要走过(x)然后再折回来,这时候有一个很棒的处理方式:考虑以时间为(x)轴,位置为(y)轴建立坐标系,那么一种可行的方案画出来大概长这样:

  这个时候我们将第一次走到(x)的那个时刻之后的线段沿直线翻折上去,因为原来的终点(ed)(<x)的,所以翻折之后新的终点一定是(>x)的,然后用这种方式我们就将一种(ed<x)的方案与唯一一种(ed>x)的方案对应上了,我们可以用计算(x<ed)的方式计算

  再加上(ed=x)的情况,得到(P_i(x)=1-(F(x)-2sumlimits_{j=x+1}^{+infty}F(j)))

  所以只要预处理出(F)的后缀和以及每个人可能到达的点的并集就好啦ovo

  

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define pb push_back
using namespace std;
const int N=120000000,MOD=998244353,inf=2147483647;
struct seg{
	int l,r;
	seg(int _l=0,int _r=0){l=_l; r=_r;}
	bool merge(int l1,int r1){
		if (r1<l||r<l1) return 0;
		l=min(l,l1);
		r=max(r,r1);
		return 1;
	}
};
vector<seg> a;
int fac[N],invfac[N];
int sum[N];
int p[100010],st[100010];
int n,m,inv2;
int ans,L,R;
int mul(int x,int y){return 1LL*x*y%MOD;}
int plu(int x,int y){return (1LL*x+y)-(1LL*x+y>=MOD?MOD:0);}
int ksm(int x,int y){
	int ret=1,base=x;
	for (;y;y>>=1,base=mul(base,base))
		if (y&1) ret=mul(ret,base);
	return ret;
}
int C(int n,int m){return n<m?0:mul(fac[n],mul(invfac[m],invfac[n-m]));}
int F(int x){
	if ((x-n)&1) return 0;
	return mul(inv2,C(n,(n+x)/2));
}
void prework(int n){
	fac[0]=1;
	for (int i=1;i<=n;++i) fac[i]=mul(fac[i-1],i);
	invfac[n]=ksm(fac[n],MOD-2);
	for (int i=n-1;i>=0;--i) invfac[i]=mul(invfac[i+1],i+1);
	int tmp=ksm(2,MOD-2);
	inv2=ksm(ksm(2,n),MOD-2);
	sum[n+1]=0;
	for (int i=n;i>=1;--i) sum[i]=plu(sum[i+1],F(i));
}
int solve(int id){
	int tmp,x,p=1;
	int ret=0;
	for (int i=a[id].l;i<=a[id].r;++i){
		p=1;
		for (int j=1;j<=m;++j){
			x=abs(st[j]-i);
			if (x>n) continue;
			tmp=plu(1,MOD-plu(F(x),mul(2,sum[x+1])));
			p=mul(p,tmp);
		}
		ret=plu(ret,plu(1,MOD-p));
	}
	ret+=ret<0?MOD:0;
	return ret;
}

int main(){
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
#endif
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;++i) scanf("%d",st+i);
	sort(st+1,st+1+m);
	prework(n);
	int cnt=-1;
	for (int i=1;i<=m;++i){
		if (a.empty()) a.pb(seg(st[i]-n,st[i]+n)),++cnt;
		else{
			if (!a[cnt].merge(st[i]-n,st[i]+n))
				a.pb(seg(st[i]-n,st[i]+n)),++cnt;
		}
	}
	ans=0;
	for (int i=0;i<=cnt;++i)
		ans=plu(ans,solve(i));
	printf("%d
",ans);
}
原文地址:https://www.cnblogs.com/yoyoball/p/10269238.html