CF1286D

CF1286D - LCC

题目大意

给定(n)个点,每个点初始在(x_i),速度为(v_i),且有(p_i)概率向右走,(1-p_i)向左走

定义一种状态的权值为最先碰撞的两个点碰撞的时间(如果没有碰撞则为0)

求期望权值


分析

显然第一次碰撞一定发生在相邻两个点之间,因此不同的碰撞时间只有最多(O(n))

把所有碰撞情况存储下来排序,每一种状态可以用(st_i=(p,a,b))描述,(a,bin{leftarrow, ightarrow})

表示(p-1)状态为(a),(p)状态为(b)

那么强制某一个碰撞(st_i)为最小碰撞,就是所有(st_j,j<i)都不发生,且(st_i)必须发生

考虑需要求解的关系涉及两个元,因此可以存进(dp)状态里,类似动态(dp),用数据结构维护

const int N=1e5+10,INF=1e9+10,P=998244353;

int n;
int x[N],v[N],p[N];

ll qpow(ll x,ll k=P-2) {
	ll res=1;
	for(;k;k>>=1,x=x*x%P) if(k&1) res=res*x%P;
	return res;
}
const int inv=qpow(100);

int bit,s[N<<2][2][2];
void Up(int p){
	memset(s[p],0,16);
	rep(i,0,1) rep(j,0,1) rep(k,0,1) s[p][i][k]=(s[p][i][k]+1ll*s[p<<1][i][j]*s[p<<1|1][j][k])%P;
}
int pos[N];
void Build(int p=1,int l=1,int r=n) {
	if(l==r) {
		pos[l]=p;
		rep(a,0,1) {
			s[p][a][0]=1ll*(100-::p[l])*inv%P;
			s[p][a][1]=1ll*::p[l]*inv%P;
		}
		return;
	}
	int mid=(l+r)>>1;
	Build(p<<1,l,mid),Build(p<<1|1,mid+1,r);
	Up(p);
}

struct Node{
	int x,y;
	int i,a,b;
	int operator < (const Node __) const{ return 1ll*x*__.y<1ll*y*__.x; }
} A[N*2];
int C;

int t[2][2];

int main(){
	n=rd();
	rep(i,1,n) x[i]=rd(),v[i]=rd(),p[i]=rd();
	rep(i,2,n) {
		A[++C]=(Node){x[i]-x[i-1],v[i]+v[i-1],i,1,0};
		if(v[i-1]<v[i]) A[++C]=(Node){x[i]-x[i-1],v[i]-v[i-1],i,0,0};
		if(v[i-1]>v[i]) A[++C]=(Node){x[i]-x[i-1],v[i-1]-v[i],i,1,1};
	}
	sort(A+1,A+C+1);
	int ans=0;
	Build();
	rep(i,1,C) {
		int val=A[i].x*qpow(A[i].y)%P;
		
		int p=pos[A[i].i];
		rep(a,0,1) rep(b,0,1) if(a!=A[i].a || b!=A[i].b) swap(s[p][a][b],t[a][b]);
		while(p>1) Up(p>>=1);

		ans=(ans+1ll*(s[1][0][0]+s[1][0][1])*val)%P;
		
		p=pos[A[i].i];
		rep(a,0,1) rep(b,0,1) if(a!=A[i].a || b!=A[i].b) swap(s[p][a][b],t[a][b]);
		else s[p][a][b]=0;
		while(p>1) Up(p>>=1);
	}
	printf("%d
",ans);
}
原文地址:https://www.cnblogs.com/chasedeath/p/14830159.html