CTSC 2017 遊戲[機率dp 線段樹]

小 R 和室友小 B 在寢室裏玩遊戲。他們一共玩了 $n$ 局遊戲,每局遊戲的結果要麼是小 R 獲勝,要麼是小 B 獲勝。php

第 $1$ 局遊戲小 R 獲勝的機率是 $p_1$,小 B 獲勝的機率是 $1-p_1$。除了第一局遊戲以外,每一局遊戲小 R 獲勝的機率與上一局遊戲小 R 是否獲勝有關。ios

具體來講:算法

  1. 若是第 $i-1\ (1< i\le n)$ 局遊戲小 R 獲勝,那麼第 $i$ 局遊戲小 R 獲勝的機率爲 $p_i$,小 B 獲勝的機率爲 $1-p_i$。
  2. 若是第 $i-1\ (1< i\le n)$ 局遊戲小 B 獲勝,那麼第 $i$ 局遊戲小 R 獲勝的機率爲 $q_i$,小 B 獲勝的機率爲 $1-q_i$。

小 D 時常過來看小 R 和小 B 玩遊戲,所以他知道某幾局遊戲的結果。他想知道在他已知信息的條件下,小 R 在 $n$ 局遊戲中獲勝總局數的指望是多少。app

小 D 記性不太好,有時他會回憶起某局遊戲的結果,並把它加入到已知信息中;有時他會忘記以前某局遊戲結果,並把它從已知信息中刪除。你的任務是:每當小 D 在已知信息中增長或刪除一條信息時,根據小 D 記得的已知信息,幫助小 D 計算小 R 在 $n$ 局遊戲中獲勝總局數的指望是多少。測試

須要注意的是:若是小 D 忘了一局遊戲的結果,以後又從新記起,兩次記憶中的遊戲結果不必定是相同的。你不須要關心小 D 的記憶是否與實際狀況相符,你只須要根據他的記憶計算相應的答案。ui

輸入格式

第一行兩個正整數 $n,m$ 和一個字符串 $type$。表示小 R 和小 B 一共玩了 $n$ 局遊戲,小 D 一共進行了 $m$ 次修改已知信息的操做,該數據的類型爲 $type$。$type$ 字符串是爲了能讓你們更方便地得到部分分,你可能不須要用到這個輸入,其具體含義見限制與約定spa

接下來 $n$ 行,第 $1$ 行包含一個實數 $p_1$,表示第一局比賽小R獲勝的機率是 $p_1$。第 $i\ (1< i \le n)$ 行包含兩個實數 $p_i,q_i$。表示在第 $i-1$ 局遊戲小 R 獲勝的狀況下,第 $i$ 局遊戲小 R 獲勝的機率是 $p_i$;$q_i$ 表示在第 $i-1$ 局遊戲小 B 獲勝的狀況下,第 $i$ 局遊戲小 R 獲勝的機率是 $q_i$。code

接下來 $m$ 行,每行描述一個小 D 已知信息的變化,操做分爲兩類。blog

  1. add i c 表示小 D 回憶起了第 $i$ 局比賽的結果,並把它加入到已知信息中。若 $c=0$ 表示第 $i$ 局比賽小 B 獲勝,若 $c=1$ 表示第 $i$ 局比賽小 R 獲勝。數據保證 $i,c$ 均爲整數且 $1\le i \le n,0\le c \le 1$,若是這個操做不是第一個操做,保證在上一個操做結束後的已知信息中沒有第 $i$ 局比賽的結果。
  2. del i 表示小 D 忘記了第 $i$ 局比賽的結果,並把它從已知信息中刪除。數據保證 $i$ 是整數且 $1\le i \le n$,保證在上一個操做結束後的已知信息中有第 $i$ 局比賽的結果。

輸出格式

對於每一個操做,輸出一行實數,表示操做結束後,在當前已知信息的條件下,小R在 $n$ 局遊戲中總共獲勝的局數的指望是多少。遊戲

樣例一

input

3 3 A
0.3
0.5 0.2
0.9 0.8
add 1 1
add 3 0
del 1

output

2.350000
1.333333
0.432749

explanation

運用貝葉斯公式

第一問

$$p(x_2=1|x_1=1)=0.5,p(x_3=1|x_1=1)=0.5*0.9+0.5*0.8=0.85,E(x_1+x_2+x_3|x_1=1)=0.5+0.85+1=2.35$$

第二問

$$p(x_2=1|x_1=1,x_3=0)=\frac{p(x_3=0|x_1=1,x_2=1)p(x_2=1|x_3=0)}{p(x_3=0|x_1=1)} \approx 0.333,E(x_1+x_2+x_3|x_1=1,x_3=0) \approx 1.333$$

第三問

$$p(x_2=1|x_3=0)=\frac{p(x_3=0|x_2=1)p(x_2=1)}{p(x_3=0)}$$

其中

$$p(x_3=0|x_2=1)=0.1,p(x_2=1)=0.3*0.5+0.7*0.2=0.29,p(x_3=0)=0.29*0.1+0.71*0.2=0.171$$

因此

$$p(x_2=1|x_3=0)=0.1*0.29/0.171 \approx 0.16959$$

$$p(x_1=1|x_3=0)=\frac{p(x_3=0|x_1=1)p(x_1=1)}{p(x_3=0)}$$

其中

$$p(x_3=0|x_1=1)=0.5*0.1+0.5*0.2=0.15,p(x_1=1)=0.3,p(x_3=0)=0.171$$

因此

$$p(x_1=1|x_3=0)=0.15*0.3/0.171 \approx 0.26316$$

$$E(x_1+x_2+x_3|x_3=0) \approx 0.43275$$

樣例二

見樣例數據下載。

樣例三

見樣例數據下載。

評分標準

若是你的答案與正確答案的絕對偏差在 $10^{-4}$ 之內,則被斷定爲正確。

若是你的全部答案均爲正確,則得滿分,不然得 0 分。

請注意輸出格式:每行輸出一個答案,答案只能爲一個實數。每行的長度不得超過 50。錯誤輸出格式會被斷定爲 0 分。

限制與約定

對於100%的數據,$1\le n\le 200000, 1\le m \le 200000,0 < p_i,q_i < 1$。

對於100%的數據,輸入保留最多四位小數

本題共有20個數據點,每一個數據點5分,每一個測試點的具體約定以下表:

測試點 $n$ $m$ 數據類型
1-2 $\le 10$ $\le 20$ A
3-4 $\le 100$ $\le 100$ B
5-6 $\le 1000$ $\le 5000$ A
7-9 $\le 2000$ $\le 5000$ B
10-13 $\le 10000$ $\le 200000$ B
14-15 $\le 200000$ $\le 200000$ C
16-17 D
18-20 A

數據類型的含義:

A:無限制

B:$\forall i > 1,|p_i-q_i| > 0.999$

C:同一時刻,小 D 最多隻有 1 條已知信息

D:同一時刻,小 D 最多隻有 5 條已知信息

時間限制:$1\texttt{s}$

空間限制:$512\texttt{MB}$

小R教你學數學

可能會用到如下公式

  1. 條件機率的計算方法

    咱們記 $p(A|B)$ 表示在已知事件 $B$ 發生時事件 $A$ 發生的機率,條件機率能夠用如下公式計算:

    $$p(A|B)=\frac{p(AB)}{p(B)}$$

    其中$p(AB)$表示事件 $B$ 和事件 $A$ 同時發生的機率,$p(B)$ 表示事件 $B$ 發生的機率。

  2. 貝葉斯公式(Bayes)

    由條件機率的計算方法,咱們容易獲得貝葉斯公式

    $$p(A|B)=\frac{p(B|A)p(A)}{p(B)}$$

  3. 全機率公式

    若是隨機變量 $x$ 有 $k$ 個取值,分別爲 $x_1,x_2,\ldots,x_k$ 那麼

    $$p(A)=\sum_{i=1}^k p(A|x=x_i)p(x=x_i)$$

舒適提示

在本題中,若是你但願得到所有的分數,你可能須要考慮因爲浮點數運算引入的偏差。只使用加法和乘法運算不會引入太大的偏差,但請謹慎使用減法和除法。

  1. 兩個大小相近的數相減能夠引入很是大的相對偏差。
  2. 若是一個矩陣的行列式值很是小,那麼求解該矩陣的逆能夠帶來至關大的偏差。

固然,若是你的算法在數學上是正確的,但沒有考慮浮點數運算的偏差問題,可能仍然能夠得到一部分的分數。

下載

樣例數據下載

 【題解】

  • 貝葉斯證實;
    \[ \begin{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)(1\lt 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} \]

 

【代碼】

  • #include<map>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define fi first
    using std::map;
    const int N=2e5+5;
    int n,m;double ans,p[N],q[N];char opt[10];
    map<int,int>S;
    map<int,int>::iterator it,nxt,pre;
    struct Matrix{
        double s[2][2];
        Matrix(){memset(s,0,sizeof s);}
        Matrix operator +(const Matrix &a)const{
            Matrix c;
            for(int i=0;i<2;i++){
                for(int j=0;j<2;j++){
                    c.s[i][j]=s[i][j]+a.s[i][j];
                }
            }
            return c;
        }
        Matrix operator *(const Matrix &a)const{
            Matrix c;
            for(int i=0;i<2;i++){
                for(int j=0;j<2;j++){
                    for(int k=0;k<2;k++){
                        c.s[i][j]+=s[i][k]*a.s[k][j];
                    }
                }
            }
            return c;
        }
    };
    struct data{Matrix mul,sum;}tr[N<<2];
    data operator +(const data &a,const data &b){
        data c;
        c.mul=a.mul*b.mul;
        c.sum=a.mul*b.sum+a.sum*b.mul;
        return c;
    }
    #define lch k<<1
    #define rch k<<1|1
    void build(int k,int l,int r){
        if(l==r){
            tr[k].mul.s[0][0]=1-q[l];
            tr[k].mul.s[0][1]=q[l];
            tr[k].mul.s[1][0]=1-p[l];
            tr[k].mul.s[1][1]=p[l];
            
            tr[k].sum.s[0][1]=q[l];
            tr[k].sum.s[1][1]=p[l];
            return ;
        }
        int mid=l+r>>1;
        build(lch,l,mid);
        build(rch,mid+1,r);
        tr[k]=tr[lch]+tr[rch];
    }
    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(lch,l,mid,x,y);
        else if(x>mid) return query(rch,mid+1,r,x,y);
        else return  query(lch,l,mid,x,mid)+query(rch,mid+1,r,mid+1,y);
    }
    double ask(int l,int r){
        data tmp=query(1,0,n+1,l+1,r);
        return tmp.sum.s[S[l]][S[r]]/tmp.mul.s[S[l]][S[r]];
    }
    int main(){
        scanf("%d%d%*s%lf",&n,&m,&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=m,x,y;i;i--){
            scanf("%s%d",opt,&x);
            if(opt[0]=='a'){
                scanf("%d",&y);S[x]=y;
                it=S.lower_bound(x);
                nxt=pre=it;pre--,nxt++;
                ans+=ask(pre->fi,it->fi);
                ans+=ask(it->fi,nxt->fi);
                ans-=ask(pre->fi,nxt->fi);
            }
            else{
                it=S.lower_bound(x);
                nxt=pre=it;pre--,nxt++;
                ans-=ask(pre->fi,it->fi);
                ans-=ask(it->fi,nxt->fi);
                ans+=ask(pre->fi,nxt->fi);
                S.erase(it);
            }
            printf("%.10lf\n",ans);
        }
        return 0;
    }
相關文章
相關標籤/搜索