CF1286D LCC

Link
不难证明第一次相遇的两个点一定相邻,这是显然的。
如果我们确定了第一次相遇的点对以及其运动状态,那么我们就确定了相遇的时间,且其它的点对都不能比它更早相遇,因此考虑将所有相遇的方案按时间升序排序之后依次处理。
(f_{i,0/1})表示考虑到第(i)个点,上一个点的运动状态为(0/1),且满足枚举的限制的概率。转移是trivial的。
将dp的转移写成(2 imes2)矩阵的形式,那么我们关心的就是(n-1)个转移矩阵的乘积。
这样从计算完一个方案考虑下一个方案时,只需要修改(1)个转移矩阵了,线段树维护即可。

#include<cctype>
#include<cstdio>
#include<algorithm>
using i64=long long;
const int N=100007,M=2000007,P=998244353;
char ibuf[1<<22],*iS=ibuf;i64 inv[M];int x[N],v[N],p[N];
struct matrix{i64 a[2][2];matrix(){a[0][0]=a[0][1]=a[1][0]=a[1][1]=0;}i64*operator[](int x){return a[x];}}b[N],t[4*N];
matrix operator*(matrix&a,matrix&b){matrix c;for(int i=0;i<2;++i)for(int j=0;j<2;++j)for(int k=0;k<2;++k)(c[i][k]+=a[i][j]*b[j][k])%=P;return c;}
struct node{int x,v,id;i64 *pos;}a[2*N];
int read(){int x=0,f=1;while(isspace(*iS))++iS;if(*iS=='-')f=-1,++iS;while(isdigit(*iS))(x*=10)+=*iS++&15;return f*x;}
int calpr(){return (p[1]*(t[1][1][0]+t[1][1][1])+(100-p[1])*(t[1][0][0]+t[1][0][1]))%P*inv[100]%P;}
#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)/2)
void pushup(int p){t[p]=t[ls]*t[rs];}
void build(int p,int l,int r)
{
    if(l==r) return t[p]=b[l],void();
    build(ls,l,mid),build(rs,mid+1,r),pushup(p);
}
void update(int p,int l,int r,int x)
{
    if(l==r) return t[p]=b[x],void();
    x<=mid? update(ls,l,mid,x):update(rs,mid+1,r,x),pushup(p);
}
#undef ls
#undef rs
#undef mid
int main()
{
    fread(ibuf,1,1<<22,stdin);
    int n=read(),m=0;i64 ans=0;
    inv[0]=inv[1]=1;for(int i=2;i<=2000000;++i) inv[i]=(P-P/i)*inv[P%i]%P;
    if(n==1) return puts("0"),0;
    for(int i=1;i<=n;++i) x[i]=read(),v[i]=read(),p[i]=read();
    for(int i=1;i<n;++i)
    {
	for(int j=0;j<2;++j) for(int k=0;k<2;++k) b[i][j][k]=inv[100]*(k? p[i+1]:100-p[i+1])%P;
	int d=x[i+1]-x[i];a[++m]={d,v[i+1]+v[i],i,&b[i][1][0]};
	if(v[i]<v[i+1]) a[++m]={d,v[i+1]-v[i],i,&b[i][0][0]};
	if(v[i]>v[i+1]) a[++m]={d,v[i]-v[i+1],i,&b[i][1][1]};
    }
    build(1,1,n-1),std::sort(a+1,a+m+1,[](const node&a,const node&b){return 1ll*a.x*b.v<1ll*b.x*a.v;});
    for(int i=1,x;i<=m;++i) x=calpr(),*a[i].pos=0,update(1,1,n-1,a[i].id),(ans+=a[i].x*inv[a[i].v]%P*(P+x-calpr()))%=P;
    printf("%lld",ans);    
}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/13037670.html