【CF712E】Memory and Casinos(数学 期望 DP)

题目链接

大意

给出一个序列,当你在某个点时,有一个向右走的概率\(P_i\)(向左为\(1-P_i\)),
给出\(M\)个操作,操作有两类:

1 X Y Z:把\(P_X\)的值修改为\(\frac{Y}{Z}\)
2 L R:询问你从\(L\)出发,随机游走,在不经过\(L-1\)的情况下到达\(R+1\)的概率

思路

我们对于一个区间设有两个值\(ValL,ValR\)
分别表示从这段区间的左端点出发能赢的概率与从它的右端点出发能赢的概率。
即我们要求的是任意区间的\(ValL\).

考虑一个区间的\(Val\)如何从它的两个子区间转移而来。

首先对于\(ValL\)
肯定有一个\(S1.ValL\times S2.ValL\),表示从\(S1\)的左端点出发到达\(S2\)左端点,再到\(R+1\),但是明显会漏掉在\(S1,S2\)间反复横跳的情况。
我们不妨枚举一下它横跳的次数来计算
\[\sum_{i=0}^{\infty}S1.ValR^i\times (1-S2.ValL)^i\]
化简为\[\frac{1}{1-S1.ValR\times (1-S2.ValL)}\]
\[ValL=\frac{S1.ValL\times S2.ValL}{1-S1.ValR\times (1-S2.ValL)}\]


同理,对于\(ValR\),也有横跳的情况,但向左向右横跳的次数就有差距了。
\[(1-S2.ValR)\times S2.ValL\times \sum_{i=0}^{\infty}S1.ValR^{i+1}\times (1-S2.ValL)^i\]
化简为\[\frac{(1-S2.ValR)\times S2.ValL\times S1.ValR}{1-S1.ValR\times (1-S2.ValL)}\]
同时,\(ValR\)也有不横跳的情况,即\(S2.ValR\).
综合一下
\[ValR=S2.ValR+\frac{(1-S2.ValR)\times S2.ValL\times S1.ValR}{1-S1.ValR\times (1-S2.ValL)}\]

对于ValL与ValR,可以使用线段树维护。

代码

没打重载,暴力合并

#include<cstdio>
#include<algorithm>
using namespace std;
#define fi first
#define se second
const double ONE=1.0;
const int MAXN=100005;
const int INF=0X3F3F3F3F;
int N,Q;
double P[MAXN];
struct Node{
    int l,r;pair<double,double>val;
}s[MAXN*8];
void Push_Up(int rt){
    pair<double,double>ret1=s[rt*2].val,ret2=s[rt*2+1].val;
    s[rt].val.fi=ret1.fi*ret2.fi/(1-ret1.se*(1-ret2.fi));
    s[rt].val.se=ret2.se+(1-ret2.se)*ret2.fi*ret1.se/(1-ret1.se*(1-ret2.fi));
}
void Build(int rt,int l,int r){
    s[rt].l=l;s[rt].r=r;
    s[rt].val.fi=s[rt].val.se=-INF;
    if(l==r){
        s[rt].val.fi=P[l];
        s[rt].val.se=P[l];
        return ;
    }
    int mid=(l+r)/2;
    Build(rt*2,l,mid);
    Build(rt*2+1,mid+1,r);
    Push_Up(rt);
}
void Insert(int rt,int p,double val){
    if(s[rt].l>p||s[rt].r<p)return ;
    if(s[rt].l==s[rt].r){s[rt].val.fi=s[rt].val.se=val;return ;}
    Insert(rt*2,p,val);Insert(rt*2+1,p,val);Push_Up(rt);
}
pair<double,double>Query(int rt,int l,int r){
    pair<double,double>ret;ret.fi=ret.se=-INF;
    if(s[rt].l>r||s[rt].r<l)return ret;
    if(s[rt].l>=l&&s[rt].r<=r)return s[rt].val;
    pair<double,double>ret1,ret2;
    ret1=Query(rt*2,l,r);
    ret2=Query(rt*2+1,l,r);
    if(ret1.fi==-INF&&ret2.fi==-INF)return ret;
    if(ret1.fi==-INF)ret=ret2;
    else if(ret2.fi==-INF)ret=ret1;
    else{
        ret.fi=ret1.fi*ret2.fi/(1-ret1.se*(1-ret2.fi));
        ret.se=ret2.se+(1-ret2.se)*ret2.fi*ret1.se/(1-ret1.se*(1-ret2.fi));
    }
    return ret;
}
int main(){
    scanf("%d%d",&N,&Q);
    for(int i=1,A,B;i<=N;i++){
        scanf("%d%d",&A,&B);
        P[i]=ONE*A/B;
    }
    Build(1,1,N);
    for(int i=1,k,x,y,z;i<=Q;i++){
        scanf("%d%d%d",&k,&x,&y);
        if(k==1){
            scanf("%d",&z);
            Insert(1,x,ONE*y/z);
        }
        if(k==2)printf("%.10f\n",Query(1,x,y).fi);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ftotl/p/11771284.html