• 【loj2263】【CTSC2017】游戏


    题目

    (R)和小(B)一共完了(n)局游戏,第一局小(R)获胜的概率为(p_i),没有平局,对于第$ i $局游戏:

    1. 如果第(i-1)局游戏小$ R (获胜,那么第 局游戏小) R $获胜的概率为 (p_i),小$ B $获胜的概率为 (1-p_i)
    2. 如果第(i-1)局游戏小(B)获胜,那么第 局游戏小$ R $获胜的概率为 (q_i),小$ B $获胜的概率为 (1-q_i)

    (m)次两种操作:

    ​ 1 (add i c) 加入第(i)局比赛的结果;

    ​ 2$del i ( 忘记第)i$局比赛的结果;

    输出每次比赛小(R)获胜局数的期望;

    (1 le n,m le 200000)

    题解

    • 根据期望的线性性考虑每一局获胜的概率,每一局获胜的概率只和相邻的两个确定的局面有关系;

      [egin{align} &bayes公式:\ P(A|B)P(B) &= P(A cap B) Leftrightarrow P(A|B) = frac{P(B|A)P(A)}{P(B)} \ &P(x_i=1|x_l=a,x_r=b)(1lt i le r)\ &=frac{P(x_i=1,x_l=a,x_r=b)}{P(x_l=a,x_r=b)}\ &=frac{P(x_i=1,x_l=a,x_r=b)}{P(x_l=a)P(x_r=b|x_l=a)}\ &=frac{P(x_i=1,x_r=b|x_l=a)}{P(x_r=b|x_l=a)}\ end{align} ]

    • 把转移写成矩阵(A_i),注意到分母即((Pi_{i>l}^{r}A_i)_{a,b}),是个定值

    • 分母求和即((sum_{i>l}^{r} Pi_{j gt l}^{j lt i} A_j imes B_i imes Pi_{j gt i}^{j lt r} A_j)_{a,b}),即将(A_i)换成一个只允许转移到1的矩阵(B_i),可以用线段树维护

    • 插入和删除用(set)维护即可

      #include<bits/stdc++.h>
      #define ls (k<<1)
      #define rs (k<<1|1)
      #define ld double
      #define fi first
      #define se second
      #define ls (k<<1)
      #define rs (k<<1|1)
      using namespace std;
      const int N=200010;
      int n,m;
      char op[10];
      map<int,int>S;
      map<int,int>::iterator it,pre,nxt;
      ld p[N],q[N],ans;
      struct Mat{
      	ld c[2][2];
      	Mat operator +(const Mat&A)const{
      		Mat re;
      		for(int i=0;i<2;++i)
      		for(int j=0;j<2;++j){
      			re.c[i][j]=c[i][j]+A.c[i][j];
      		}
      		return re;
      	}
      	Mat operator *(const Mat&A)const{
      		Mat re;
      		for(int i=0;i<2;++i)
      		for(int j=0;j<2;++j){
      			re.c[i][j]=0;
      			for(int k=0;k<2;++k)re.c[i][j]+=c[i][k]*A.c[k][j];
      		}
      		return re;
      	}
      };
      struct data{Mat mul,sum;}tr[N<<2];
      data operator +(data A,data B){
      	data re;
      	re.mul=A.mul*B.mul;
      	re.sum=A.mul*B.sum+A.sum*B.mul;
      	return re;
      }
      void build(int k,int l,int r){
      	if(l==r){
      		tr[k].mul.c[1][1]=p[l];
      		tr[k].mul.c[1][0]=1-p[l];
      		tr[k].mul.c[0][1]=q[l];
      		tr[k].mul.c[0][0]=1-q[l];
      		tr[k].sum.c[1][1]=p[l];
      		tr[k].sum.c[0][1]=q[l];
      		return;
      	}
      	int mid=(l+r)>>1;
      	build(ls,l,mid);
      	build(rs,mid+1,r);
      	tr[k]=tr[ls]+tr[rs];
      }
      data query(int k,int l,int r,int x,int y){
      	if(l==x&&r==y)return tr[k];
      	int mid=(l+r)>>1;
      	if(y<=mid)return query(ls,l,mid,x,y);
      	else if(x>mid)return query(rs,mid+1,r,x,y);
      	else return query(ls,l,mid,x,mid)+query(rs,mid+1,r,mid+1,y);
      }
      ld ask(int l,int r){
      	data tmp=query(1,0,n+1,l+1,r);
      	return tmp.sum.c[S[l]][S[r]]/tmp.mul.c[S[l]][S[r]];
      }
      int main(){
      //	freopen("game.in","r",stdin);
      //	freopen("game.out","w",stdout);
      	scanf("%d%d%s%lf",&n,&m,op,&p[1]);
      	for(int i=2;i<=n;++i)scanf("%lf%lf",&p[i],&q[i]);
      	p[0]=q[0]=1;
      	S[0]=1;S[n+1]=0;
      	build(1,0,n+1);
      	ans=ask(0,n+1);
      	for(int i=1,x,y;i<=m;++i){
      		scanf("%s%d",op,&x);
      		if(op[0]=='a'){
      			scanf("%d",&y);S[x]=y;
      			it=S.lower_bound(x);
      			pre=it,--pre;nxt=it,++nxt;
      			ans-=ask((*pre).fi,(*nxt).fi);
      			ans+=ask((*pre).fi,(*it).fi);
      			ans+=ask((*it).fi,(*nxt).fi);
      		}else{
      			it=S.lower_bound(x);
      			pre=it,--pre;nxt=it,++nxt;
      			ans-=ask((*pre).fi,(*it).fi);
      			ans-=ask((*it).fi,(*nxt).fi);
      			ans+=ask((*pre).fi,(*nxt).fi);
      			S.erase(it);
      		}
      		printf("%.10lf
      ",ans);
      	}
      	return 0;
      }
      
  • 相关阅读:
    C++ 函数返回数组指针的问题
    cmake 静态调用 c++ dll 的类的一个例子(Clion IDE)[更新1:增加1.模版的应用,2.ma 的算法]
    一月5日
    一月5日
    一月5日
    一月5日
    一月5日
    一月5日
    一月5日
    一月5日
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/10826072.html
Copyright © 2020-2023  润新知