CF1286D - LCC

CF1286D - LCC

题目大意

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

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

求期望权值


分析

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

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

表示\(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\n",ans);
}
posted @ 2021-05-31 09:55  chasedeath  阅读(84)  评论(0编辑  收藏  举报