题目
小(R)和小(B)一共完了(n)局游戏,第一局小(R)获胜的概率为(p_i),没有平局,对于第$ i $局游戏:
- 如果第(i-1)局游戏小$ R (获胜,那么第 局游戏小) R $获胜的概率为 (p_i),小$ B $获胜的概率为 (1-p_i)
- 如果第(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; }