洛谷P3772/LOJ2263/UOJ299/BZOJ4902[CTSC2017]游戏(概率期望+矩阵+线段树)
一个显然结论是每次的期望只和前后最近的已知结果有关。
另一个结论是:若$[x,y]$内$x$次胜负状态为$a$,$y$次为$b$的期望胜利次数为$E$,概率为$P$,则钦定$x$,$y$次分别为$a$,$b$后期望为$\frac{E}{P}$。(这个可以由贝叶斯定理想)
而固定起点的$E_0,E_1$,$P_0,P_1$可以由前一个推出,典型矩阵的套路,线段树维护即可。
但是注意期望是要相加的,也就是线段树合并期望矩阵的时候要写$matE_o=matE_{lc}\times matP_{rc}+matP_{lc}\times matE{rc}$(左区间期望*这一状态在右区间的概率=左区间对完整区间期望的贡献,右区间同理),注意矩阵没有交换律,不要乘反!
#include<cstdio> #include<cstring> #include<set> using namespace std; const int N=200050; char opt[5]; int n; bool d[N]; double p[N],q[N]; set<int> S; struct mat{ double a[2][2]; mat(){a[0][0]=a[0][1]=a[1][0]=a[1][1]=0;} mat(double w,double x,double y,double z){a[1][1]=w;a[1][0]=x;a[0][1]=y;a[0][0]=z;} inline mat operator +(const mat &b)const{return mat(a[1][1]+b.a[1][1],a[1][0]+b.a[1][0],a[0][1]+b.a[0][1],a[0][0]+b.a[0][0]);} inline mat operator *(const mat &b)const{return mat(a[1][0]*b.a[0][1]+a[1][1]*b.a[1][1],a[1][0]*b.a[0][0]+a[1][1]*b.a[1][0],a[0][0]*b.a[0][1]+a[0][1]*b.a[1][1],a[0][0]*b.a[0][0]+a[0][1]*b.a[1][0]);} }; struct node{ mat E,P; node(){} node(mat E,mat P):E(E),P(P){} inline node operator +(const node &b)const{return node(E*b.P+P*b.E,P*b.P);} }sum[N<<2]; void build(int o,int L,int R){ if(L==R)sum[o]=node(mat(p[L],0,q[L],0),mat(p[L],1-p[L],q[L],1-q[L])); else{ int lc=o<<1,rc=lc|1,M=L+R>>1; build(lc,L,M);build(rc,M+1,R); sum[o]=sum[lc]+sum[rc]; } } node ask(int o,int L,int R,int x,int y){ if(x<=L&&y>=R)return sum[o]; else{ int lc=o<<1,rc=lc|1,M=L+R>>1; if(x<=M)if(y>M)return ask(lc,L,M,x,y)+ask(rc,M+1,R,x,y); else return ask(lc,L,M,x,y); else return ask(rc,M+1,R,x,y); } } double query(int x,int y){ node s=ask(1,0,n+1,x+1,y); return s.E.a[d[x]][d[y]]/s.P.a[d[x]][d[y]]; } int main(){ int m,i,x; double ans; set<int>::iterator pre,nxt; scanf("%d%d%s%lf",&n,&m,opt,p+1); for(i=2;i<=n;++i)scanf("%lf%lf",p+i,q+i); p[0]=q[0]=1.0;d[0]=1; //第一次胜率钦定为pi,那就钦定0次赢了 S.insert(0);S.insert(n+1); build(1,0,n+1); ans=query(0,n+1); while(m--){ scanf("%s%d",opt,&i); if(opt[0]=='a'){ scanf("%d",&x);d[i]=x; //不要用scanf("%d",d+i),scanf会把4个bool当成一个int 改掉 pre=nxt=S.upper_bound(i);--pre; ans+=query(i,*nxt)+query(*pre,i)-query(*pre,*nxt); S.insert(i); }else{ pre=nxt=S.upper_bound(i);--pre;--pre; ans+=query(*pre,*nxt)-query(*pre,i)-query(i,*nxt); S.erase(++pre); } printf("%.6lf\n",ans); } return 0; }