zoukankan      html  css  js  c++  java
  • 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);    
    }
    
  • 相关阅读:
    Windows7安装SQL Server 2008图解
    【Android病毒分析报告】
    linux source命令学习
    SQL学习笔记——SQL初入门,Ubuntu下MySQL的安装
    挂断电话的实现(即类似于电话号码黑名单)
    35+雪花Logos设计灵感
    jdk8预览
    PL/SQL --> 动态SQL调用包中函数或过程
    VMware 彻底删除虚拟机操作系统的方法
    Ubuntu 16.04 LTS: apt-get update 失败处理 Aborted (core dumped)
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/13037670.html
Copyright © 2011-2022 走看看