CF712E Memory and Casinos 期望概率
阿新 • • 發佈:2019-01-03
題意:\(n\)個賭場,每個賭場有\(p_{i}\)的勝率,如果贏了就走到下一個賭場,輸了就退回上一個賭場,規定\(1\)號賭場的上一個是\(0\)號賭場,\(n\)號賭場的下一個是\(n + 1\)號賭場,一旦到達\(0\)或\(n + 1\)號賭場就相當於退出賭局了。
定義統治區間\([l, r]\)為從第\(l\)個賭場開始,到達第\(r + 1\)個賭場,且在過程中不經過\([1, l - 1]\)的賭場。維護2種操作:
1,修改一個賭場的勝率
2,詢問統治\([l, r]\)的概率
題解:
設\(f_{i}\)表示從\(x\)能走到\(n\)的概率,則有:
\[f_{i} = f_{i - 1}(1 - p_{i}) + f_{i + 1} \cdot p_{i}\]
\[f_{i} - f[i - 1] = p_{i}(f_{i + 1} - f_{i - 1})\]
令\(g_{i} = f_{i} - f_{i - 1} = p_{i} (g_{i} + g_{i + 1})\)(由上式得)
所以\(g_{i + 1} = g_{i} \cdot \frac{1 - p_{i}}{p_{i}}\),
令\(t_{i} = \frac{1 - p_{i}}{p_{i}}\),則\(g_{i + 1} = g_{i} t_{i}\)
顯然有\(f_{n} = 1(不用走就到了), f_{0} = 0(因為已經出邊界)\).
所以\(\sum_{i = 1}^{n}g_{i} = 1\)
\[g_{1} + g_{1}t_{1} + g_{1}t_{1}t_{2} + ... + g_{1}t_{1}...t_{n - 1} = 1\]
提出\(g_{1}\).
\[g_{1}(1 + t_{1} + t_{1} t_{2} + ... + t_{1}...t_{n - 1}) = 1\]
那麼我們維護\(t\)值,就可以得到\(g_{1}\)的值。
上面是求詢問區間\([1, n - 1]\)時的答案,也就是\(1\)到\(n\)的概率。
替換一下,同理可得,在詢問區間\([l, r]\)時,也就是要求\(l\)
\[g_{l}(1 + t_{l} + t_{l}t_{l + 1} + ... + t_{l}t_{l + 1}...t_{r}) = 1\]
用線段樹維護:
對於區間\([l, r]\)維護\(t_{l} + t_{l}t_{l + 1} + ... + t_{l}t_{l + 1}...t_{r}\).然後在最後加1即可。
定義node結構體,其中x表示這個區間的\(t_{l} + t_{l}t_{l + 1} + ... + t_{l}t_{l + 1}...t_{r}\),w表示\(t_{l}t_{l + 1}...t_{r}\)
那麼合併時新區間的x為\(left.x + right.x * left.w\),
w為\(left.w \cdot right.w\)
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 101000
#define ac 500000
int n, q, w;
int l[ac], r[ac];
double ans, go;
double tree[ac], p[AC], t[AC], sum[ac];
struct node{
double x, w;
};
inline int read()
{
int x = 0;char c = getchar();
while(c > '9' || c < '0') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x;
}
inline void update(int x){
int ll = x * 2, rr = ll + 1;
sum[x] = sum[ll] * sum[rr];
tree[x] = tree[ll] + tree[rr] * sum[ll];
}
void build(int x, int ll, int rr)
{
l[x] = ll, r[x] = rr;
if(ll == rr) {tree[x] = sum[x] = t[ll]; return ;}
int mid = (ll + rr) >> 1;
build(x * 2, ll, mid), build(x * 2 + 1, mid + 1, rr);
update(x);
}
void change(int x, int go, double w)
{
if(l[x] == r[x]){sum[x] = tree[x] = w; return ;}
int mid = (l[x] + r[x]) >> 1;
(go <= mid) ? change(x * 2, go, w) : change(x * 2 + 1, go, w);
update(x);
}
node find(int x, int ll, int rr)
{
if(l[x] == ll && r[x] == rr) return (node){tree[x], sum[x]};
int mid = (l[x] + r[x]) >> 1;
if(rr <= mid) return find(x * 2, ll, rr);
else if(ll > mid) return find(x * 2 + 1, ll, rr);
else
{
node now = find(x * 2, ll, mid), y = find(x * 2 + 1, mid + 1, rr);
now.x = now.x + y.x * now.w, now.w = now.w * y.w;//要更新now.w!!!
return now;
}
}
void pre()
{
n = read(), q = read();
for(R i = 1; i <= n; i ++)
{
double a = read(), b = read();
p[i] = a / b;
}
for(R i = 1; i <= n; i ++) t[i] = (1 - p[i]) / p[i];
}
void work()
{
int opt, a, b, x;
for(R i = 1; i <= q; i ++)
{
opt = read();
if(opt == 1)
{
x = read(), a = read(), b = read(), go = 1.0 * a / b;
go = (1 - go) / go, change(1, x, go);
}
else
{
a = read(), b = read();
node x = find(1, a, b);
// printf("%lf\n", x.x);
printf("%.10lf\n", 1 / (1 + x.x));
}
}
}
int main()
{
freopen("in.in", "r", stdin);
pre();
build(1, 1, n);
work();
fclose(stdin);
return 0;
}