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);
}