Memory and Casinos CodeForces - 712E (概率)

题目链接

题目大意:$n$个点, 每个点$i$有成功率$p_i$, 若成功走到$i+1$, 否则走到走到$i-1$, 多组询问, 求从$l$出发, 在$l$处不失败, 最后在$r$处胜利的概率

设$L[l,r]$表示从$l$出发, 在$l$处不失败, 最后在$r$处胜利的概率,$R[l,r]$表示从$r$出发, 在$l$处不失败, 最后在$r$处胜利的概率

记$l_1=L[l,mid],r_1=L[mid+1,r],l_2=R[l,mid],r_2=R[mid+1,r].$


枚举从$mid$到$mid+1$的次数, 可以得到下式

$$L[l,r]=l_1l_2\sum\limits_{n=0}^\infty{(1-l_2)^nr_1^n}=\frac{l_1l_2}{1-(1-l_2)r_1}$$

$$R[l,r]=r_2+(1-r_2)r_1l_2\sum\limits_{n=0}^\infty{(1-l_2)^nr_1^n}$$

$$=r_2+(1-r_2)\frac{r_1l_2}{1-(1-l_2)r_1}$$

直接用线段树维护就好了

#include <iostream>
#include <algorithm>
#include <math.h>
#include <cstdio>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define mid ((l+r)>>1)
#define lc (o<<1)
#define rc (lc|1)
#define ls lc,l,mid
#define rs rc,mid+1,r
using namespace std;

const int N = 1e5+10;
int n, m;
struct _ {
    double L, R;
    _ () {}
    _ (int x, int y) {L=R=(double)x/y;}
    _ (double l,double r) :L(l),R(r) {}
    _ operator + (const _ &rhs) const {
        return _(L*rhs.L/(1-(1-rhs.L)*R),rhs.R+(1-rhs.R)*R*rhs.L/(1-(1-rhs.L)*R));
    }
} v[N<<2];

void build(int o, int l, int r) {
    if (l==r) {
        int x, y;
        scanf("%d%d", &x, &y);
        v[o]=_(x,y);
        return;
    }
    build(ls),build(rs),v[o]=v[lc]+v[rc];
}

void upd(int o, int l, int r, int pos, int x, int y) {
    if (l==r) return v[o]=_(x,y),void();
    if (mid>=pos) upd(ls,pos,x,y);
    else upd(rs,pos,x,y);
    v[o]=v[lc]+v[rc];
}

_ qry(int o, int l, int r, int ql, int qr) {
    if (ql<=l&&r<=qr) return v[o];
    if (mid<ql) return qry(rs,ql,qr);
    if (mid>=qr) return qry(ls,ql,qr);
    return qry(ls,ql,qr)+qry(rs,ql,qr);
}

int main() {
    scanf("%d%d", &n, &m);
    build(1,1,n);
    REP(i,1,m) {
        int op, pos, a, b;
        scanf("%d", &op);
        if (op==1) {
            scanf("%d%d%d", &pos, &a, &b);
            upd(1,1,n,pos,a,b);
        } else {
            scanf("%d%d", &a, &b);
            printf("%.12lf\n", qry(1,1,n,a,b).L);
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/uid001/p/10240558.html