UOJ299 游戏

游戏

小 R 和室友小 B 在寝室里玩游戏。他们一共玩了 (n) 局游戏,每局游戏的结果要么是小 R 获胜,要么是小 B 获胜。

(1) 局游戏小 R 获胜的概率是 (p_1),小 B 获胜的概率是 (1-p_1)。除了第一局游戏之外,每一局游戏小 R 获胜的概率与上一局游戏小 R 是否获胜有关。

具体来说:

如果第 (i-1 (1< ile n)) 局游戏小 R 获胜,那么第 (i) 局游戏小 R 获胜的概率为 (p_i),小 B 获胜的概率为 (1-p_i)
如果第 (i-1 (1< ile n)) 局游戏小 B 获胜,那么第 (i) 局游戏小 R 获胜的概率为 (q_i),小 B 获胜的概率为 (1-q_i)
小 D 时常过来看小 R 和小 B 玩游戏,因此他知道某几局游戏的结果。他想知道在他已知信息的条件下,小 R 在 (n) 局游戏中获胜总局数的期望是多少。

小 D 记性不太好,有时他会回忆起某局游戏的结果,并把它加入到已知信息中;有时他会忘记之前某局游戏结果,并把它从已知信息中删除。你的任务是:每当小 D 在已知信息中增加或删除一条信息时,根据小 D 记得的已知信息,帮助小 D 计算小 R 在 (n) 局游戏中获胜总局数的期望是多少。

需要注意的是:如果小 D 忘了一局游戏的结果,之后又重新记起,两次记忆中的游戏结果不一定是相同的。你不需要关心小 D 的记忆是否与实际情况相符,你只需要根据他的记忆计算相应的答案。

对于100%的数据,(1le nle 200000, 1le m le 200000,0 < p_i,q_i < 1)

题解

贝叶斯公式的运用。

https://www.cnblogs.com/xuruifan/p/7016935.html
https://wearrys.github.io/2017/ctsc2017-game/

根据期望线性性,同样是考虑每个未被确定的游戏的胜率

感性理解一下,显然每个游戏只和两边已确定的结果有关。所以相当于根据已确定的结果划分了若干个区间。每次插入删除就是删去旧区间加入新区间

假设 (X) 两边的已知事件是 (A)(B),根据条件概率,

[P(X|A∩B)=frac{P(X∩A∩B)}{P(A∩B)}\ =frac{P((X∩B)|A)P(A)}{P(B|A)P(A)}\ =frac{P((X∩B)|A)}{P(B|A)} ]

用线段树维护矩阵就可以很方便地求出分母和分子的总和了。时间复杂度 (O(nlog n))

struct matrix {float128 v[2][2];};
IN matrix operator+(CO matrix&a,CO matrix&b){
	matrix ans;
	for(int i=0;i<2;++i)for(int j=0;j<2;++j)
		ans.v[i][j]=a.v[i][j]+b.v[i][j];
	return ans;
}
IN matrix operator*(CO matrix&a,CO matrix&b){
	matrix ans;
	for(int i=0;i<2;++i)for(int j=0;j<2;++j)
		ans.v[i][j]=a.v[i][0]*b.v[0][j]+a.v[i][1]*b.v[1][j];
	return ans;
}

struct node {matrix p,e;};
IN node operator+(CO node&a,CO node&b){
	return {a.p*b.p,a.p*b.e+a.e*b.p};
}

CO int N=2e5+10;
float128 p[N],q[N];
int S[N];
node tr[4*N];

#define lc (x<<1)
#define rc (x<<1|1)
#define mid ((l+r)>>1)
void build(int x,int l,int r){
	if(l==r){ // l-1 -> l
		tr[x].p.v[0][0]=1-q[l],tr[x].p.v[0][1]=q[l];
		tr[x].p.v[1][0]=1-p[l],tr[x].p.v[1][1]=p[l];
		tr[x].e.v[0][0]=0,tr[x].e.v[0][1]=q[l];
		tr[x].e.v[1][0]=0,tr[x].e.v[1][1]=p[l];
		return;
	}
	build(lc,l,mid),build(rc,mid+1,r);
	tr[x]=tr[lc]+tr[rc];
}
node query(int x,int l,int r,int ql,int qr){
	if(ql<=l and r<=qr) return tr[x];
	if(qr<=mid) return query(lc,l,mid,ql,qr);
	if(ql>mid) return query(rc,mid+1,r,ql,qr);
	return query(lc,l,mid,ql,qr)+query(rc,mid+1,r,ql,qr);
}
#undef lc
#undef rc
#undef mid

set<int> st;

int main(){
	int n=read<int>(),m=read<int>();
	scanf("%*s %Lf",&p[1]);
	for(int i=2;i<=n;++i) scanf("%Lf%Lf",&p[i],&q[i]);
	S[0]=1,S[n+1]=0;
	st.insert(0),st.insert(n+1);
	build(1,1,n+1);
	function<float128(int,int)> calc=[n](int l,int r){ // (l,r]
		node ans=query(1,1,n+1,l+1,r);
		return ans.e.v[S[l]][S[r]]/ans.p.v[S[l]][S[r]];
	};
	float128 ans=calc(0,n+1);
	while(m--){
		static char opt[10];scanf("%s",opt);
		if(opt[0]=='a'){
			int i=read<int>();
			read(S[i]);
			set<int>::iterator it=st.insert(i).first;
			set<int>::iterator it_l=it,it_r=it;
			--it_l,++it_r;
			int l=*it_l,r=*it_r;
			ans-=calc(l,r);
			ans+=calc(l,i)+calc(i,r);
		}
		else{
			int i=read<int>();
			set<int>::iterator it=st.find(i);
			set<int>::iterator it_l=it,it_r=it;
			--it_l,++it_r;
			int l=*it_l,r=*it_r;
			st.erase(it);
			ans-=calc(l,i)+calc(i,r);
			ans+=calc(l,r);
		}
		printf("%Lf
",ans);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/autoint/p/12507080.html