CTSC 2017 游戏[概率dp 线段树]

小 R 和室友小 B 在寝室里玩游戏。他们一共玩了 $n$ 局游戏,每局游戏的结果要么是小 R 获胜,要么是小 B 获胜。

第 $1$ 局游戏小 R 获胜的概率是 $p_1$,小 B 获胜的概率是 $1-p_1$。除了第一局游戏之外,每一局游戏小 R 获胜的概率与上一局游戏小 R 是否获胜有关。

具体来说:

  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$ 局游戏中获胜总局数的期望是多少。

小 D 记性不太好,有时他会回忆起某局游戏的结果,并把它加入到已知信息中;有时他会忘记之前某局游戏结果,并把它从已知信息中删除。你的任务是:每当小 D 在已知信息中增加或删除一条信息时,根据小 D 记得的已知信息,帮助小 D 计算小 R 在 $n$ 局游戏中获胜总局数的期望是多少。

需要注意的是:如果小 D 忘了一局游戏的结果,之后又重新记起,两次记忆中的游戏结果不一定是相同的。你不需要关心小 D 的记忆是否与实际情况相符,你只需要根据他的记忆计算相应的答案。

输入格式

第一行两个正整数 $n,m$ 和一个字符串 $type$。表示小 R 和小 B 一共玩了 $n$ 局游戏,小 D 一共进行了 $m$ 次修改已知信息的操作,该数据的类型为 $type$。$type$ 字符串是为了能让大家更方便地获得部分分,你可能不需要用到这个输入,其具体含义见限制与约定

接下来 $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$。

接下来 $m$ 行,每行描述一个小 D 已知信息的变化,操作分为两类。

  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;
    }

原文地址:https://www.cnblogs.com/shenben/p/11663499.html

时间: 2024-11-03 23:21:19

CTSC 2017 游戏[概率dp 线段树]的相关文章

[tsA1490][2013中国国家集训队第二次作业]osu![概率dp+线段树+矩阵乘法]

这样的题解只能舔题解了,,,qaq 清橙资料里有.. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cmath> 6 #include <ctime> 7 #include <algorithm> 8 9 using namespace std; 10 11 struct Mat

题解 HDU 3698 Let the light guide us Dp + 线段树优化

http://acm.hdu.edu.cn/showproblem.php?pid=3698 Let the light guide us Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 62768/32768 K (Java/Others) Total Submission(s): 759    Accepted Submission(s): 253 Problem Description Plain of despair was

[后缀数组+dp/AC自动机+dp+线段树] hdu 4117 GRE Words

题意: 给你N个字符串, N(1 <= N <= 2w), 所有串的长度加一起不超过30w.每个串有个值.这个值[-1000, 1000]. 问不打乱字符串顺序,从中取若干个字符串,使得前一个串是后一个串的子串,求满足前面调条件的字符串值得和最大,求这个值. 思路: 其实就是一个很明显的dp. dp[i]代表以第i个字符串结尾的最大权值. 但是就是子串这个问题怎么处理. 由于这题数据比较水可以用后缀数组处理这个问题. 将所有字符串拼接,做sa. 每次在height数组里往上和往下寻找公共前缀等

[JLOI2013]卡牌游戏 概率DP

[JLOI2013]卡牌游戏 概率DP 题面 \(dfs\)复杂度爆炸,考虑DP.发现决策时,我们只用关心当前玩家是从庄家数第几个玩家与当前抽到的牌是啥.于是设计状态\(f[i][j]\)表示有\(i\)个人时,从庄家数第\(j\)个人的胜率.又因为此时终态确定\(f[1][1]=1\)(只有一个人时那个人胜率为100%),所以倒推回去. 转移时,枚举抽到的牌,算出从庄家数第\(t\)个会出局,那么下一局庄家就是第\(t+1\)个,当前局第\(j\)个就是下一局的第\(j-t(t< j)\)或\

【BZOJ-2892&amp;1171】强袭作战&amp;大sz的游戏 权值线段树+单调队列+标记永久化+DP

2892: 强袭作战 Time Limit: 50 Sec  Memory Limit: 512 MBSubmit: 45  Solved: 30[Submit][Status][Discuss] Description 在一个没有冬马的世界里,经历了学园祭后的春希着急着想要见到心爱的雪菜.然而在排队想见雪菜的fans太多了,春希一时半会凑不到雪菜面前. 作为高帅富,这样的问题怎么能难倒春希?春希从武也手中拿到了取自金闪闪宝库里的多啦A梦的传话筒,并且给每一个排队的fans都发了一个传话筒. 于

HDU4719-Oh My Holy FFF(DP线段树优化)

Oh My Holy FFF Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total Submission(s): 606    Accepted Submission(s): 141 Problem Description N soldiers from the famous "*FFF* army" is standing in a line, from le

hdu3698 Let the light guide us dp+线段树优化

http://acm.hdu.edu.cn/showproblem.php?pid=3698 Let the light guide us Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 62768/32768 K (Java/Others) Total Submission(s): 821    Accepted Submission(s): 285 Problem Description Plain of despair was

hdu 4719 Oh My Holy FFF(dp线段树优化)

Oh My Holy FFF Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total Submission(s): 848    Accepted Submission(s): 219 Problem Description N soldiers from the famous "*FFF* army" is standing in a line, from le

hdu5293 Tree chain problem 树形dp+线段树

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5293 在一棵树中,给出若干条链和链的权值.求选取不相交的链使得权值和最大. 比赛的时候以为是树链剖分就果断没去想,事实上是没思路. 看了题解,原来是树形dp.话说多校第一场树形dp还真多. . .. 维护d[i],表示以i为根节点的子树的最优答案. sum[i]表示i的儿子节点(仅仅能是儿子节点)的d值和. 那么答案就是d[root]. 怎样更新d值 d[i] = max(sum[i] , w[p]+s