zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    python命名
    类的绑定方法与非绑定方法
    类的封装
    类的多态性
    python中的while循环和for循环
    python的单、双、多分支流程控制
    python中的运算符
    python中的变量
    接口与归一化设计
    类的继承
  • 原文地址:https://www.cnblogs.com/autoint/p/12507080.html
Copyright © 2011-2022 走看看