CF712E Memory and Casinos 題解

zifanwang發表於2024-03-30

假設只保留陣列上 \([l,r]\) 的這段數,記 \(f_i\) 表示從點 \(i\) 出發到達 \(n+1\) 的機率,則有 \(f_0=0,f_{n+1}=1,f_i=(1-p_i)f_{i-1}+p_if_{i+1}\),題目要求的是 \(f_1\)

考慮對最後一個等式進行一些變換,把 \(f_i\) 的係數拆開得:

\[p_if_i+(1-p_i)f_i=(1-p_i)f_{i-1}+p_if_{i+1} \]

移項得:

\[(1-p_i)(f_i-f_{i-1})=p_i(f_{i+1}-f_i) \]

\(d_i=f_{i+1}-f_i\),那麼由上式得 \(d_i=\frac{1-p_i}{p_i}d_{i-1}\)

顯然有 \(\sum_{i=0}^nd_i=1,f_1=d_0\),於是 \(f_1=\frac 1{1+\sum_{i=1}^n d_i}\),線段樹維護即可。

時間複雜度 \(\mathcal O(n\log n)\)

參考程式碼:

#include<bits/stdc++.h>
#define mxn 100003
#define ld long double
#define rep(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
struct node{
	ld s,d;
}t[mxn<<2];
int n,q,a,b;
ld d[mxn];
inline node operator+(node x,node y){
	return {x.s+x.d*(y.s-1),x.d*y.d};
}
void build(int p,int l,int r){
	if(l==r){
		t[p]={d[l]+1,d[l]};
		return;
	}
	int mid=(l+r)>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
	t[p]=t[p<<1]+t[p<<1|1];
}
void change(int p,int x,int l,int r){
	if(l==r){
		t[p]={d[l]+1,d[l]};
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid)change(p<<1,x,l,mid);
	else change(p<<1|1,x,mid+1,r);
	t[p]=t[p<<1]+t[p<<1|1];
}
node ask(int p,int l,int r,int L,int R){
	if(l<=L&&R<=r)return t[p];
	int mid=(L+R)>>1;
	if(l<=mid&&r>mid)return ask(p<<1,l,r,L,mid)+ask(p<<1|1,l,r,mid+1,R);
	if(l<=mid)return ask(p<<1,l,r,L,mid);
	return ask(p<<1|1,l,r,mid+1,R);
}
signed main(){
	scanf("%d%d",&n,&q);
	rep(i,1,n)scanf("%d%d",&a,&b),d[i]=(ld)a/b,d[i]=(1-d[i])/d[i];
	build(1,1,n);
	int op,x,l,r;
	while(q--){
		scanf("%d",&op);
		if(op==1){
			scanf("%d%d%d",&x,&l,&r);
			d[x]=(ld)l/r;
			d[x]=(1-d[x])/d[x];
			change(1,x,1,n);
		}else{
			scanf("%d%d",&l,&r);
			printf("%.9Lf\n",1/ask(1,l,r,1,n).s);
		}
	}
	return 0;
}

相關文章