[CTSC2017]游戏(Bayes定理,线段树)

传送门:http://uoj.ac/problem/299

题目良心给了Bayes定理,但对于我这种数学渣来说并没有什么用。

先大概讲下相关数学内容:

1.定义:$P(X)$ 表示事件$X$发生的概率,$E(X)$表示随机变量$X$的期望值,$P(A|B)$表示已知$B$发生,$A$发生的概率,$P(AB)$表示$A$和$B$同时发生的概率。

2.条件概率公式:

$\begin{aligned}P(A|B)=\frac{P(AB)}{P(B)}\end{aligned}$。

由$P(B)P(A|B)=P(AB)$移项可得。

3.全概率公式:

当存在$k$个互斥事件且事件并集为全集时:

$P(A)=\sum\limits_{i=1}^{k}P(A|X=X_i)P(X=Xi)$

由条件概率公式可得。

4.Bayes定理:

$\begin{aligned}P(A|B)=\frac{P(AB)}{P(B)}=\frac{P(B|A)P(A)}{P(B)}\end{aligned}$

由条件概率公式可得。

接下来是OI部分。

对于每个位置,找到夹着它的两个已知胜负条件,设为A和B。

将A作为必要条件(题设),可知$E(C)=\sum_{i=1}^{k}P(c_i=1)$。根据Bayes公式可得$\begin{aligned}P(c_i=1|B)=\frac{P(c_i=1)P(B|c_i=1)}{P(B)}\end{aligned}$

修改的时候使用线段树进行区间合并,用矩阵加速合并。

设节点$x$代表的区间是$[L,R]$,则val[x][0/1][0/1]表示$L-1$为胜/负时,R为胜/负的概率。

接下来是暴力部分(10分)。

指数级枚举所有状态,计算这个状态出现的概率以及是否合法,累加即可。

方法一:暴力

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5
 6 const int N=200100;
 7 char S[15];
 8 int n,m;
 9 double p[N],q[N],w[15];
10
11 void calc(){
12     double ans=0,tp=0;
13     int up=(1<<n);
14     for(int i=0;i<up;i++){
15         bool f=1; int c=0,las=1; double pc=1;
16         for(int j=0,k=1;j<n;j++,k++)
17             if(i&(1<<j)){
18                 if(w[k]==0){ f=false; break; }
19                 c++;
20                 if (las) pc*=p[k]; else pc*=q[k];
21                 las=1;
22             }else{
23                 if(w[k]==1){ f=false; break; }
24                 if(las)pc*=(1-p[k]); else pc*=(1-q[k]);
25                 las=0;
26             }
27         if(f)ans+=pc*c,tp+=pc;
28     }
29     ans/=tp; printf("%.6f\n",ans);
30 }
31
32 void solve(){
33     for(int i=1;i<=n;i++)w[i]=-1;
34     for(int i=1,x,y;i<=m;i++){
35         scanf("%s",S);
36         if(S[0]==‘a‘) scanf("%d%d",&x,&y),w[x]=y; else scanf("%d",&x),w[x]=-1;
37         calc();
38     }
39 }
40
41 int main(){
42     freopen("game.in","r",stdin);
43     freopen("game.out","w",stdout);
44     scanf("%d%d",&n,&m); scanf("%s",S);
45     scanf("%lf",&p[1]);
46     for(int i=2;i<=n;i++)scanf("%lf %lf",&p[i],&q[i]);
47     solve();
48     return 0;
49 }

方法二:正解

 1 #include<set>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define ls (x<<1)
 6 #define rs (ls|1)
 7 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 8 using namespace std;
 9
10 const int N=200100;
11 int n,m,p,c,type,S2[N];
12 double ans,P[N],Q[N];
13 set<int>S1;
14 char op[10];
15
16 struct M{ double v[2][2]; M(){ memset(v,0,sizeof(v)); }; };
17 M operator +(M a,const M &b){ rep(i,0,1) rep(j,0,1) a.v[i][j]+=b.v[i][j]; return a; }
18 M operator *(const M &a,const M &b){ M c; rep(i,0,1) rep(j,0,1) rep(k,0,1) c.v[i][j]+=a.v[i][k]*b.v[k][j]; return c; }
19
20 struct inf{ M f,g; inf(const M &_f=M(),const M &_g=M()):f(_f),g(_g){}; };
21 inf operator +(const inf &a,const inf &b){ return inf(a.f*b.f,a.g*b.f+a.f*b.g); }
22 struct node{ int l,r,mid; inf val; }seg[N<<2];
23
24 void build(int x,int l,int r){
25     if (l==r){
26         seg[x].val.f.v[1][1]=P[l]; seg[x].val.f.v[1][0]=1.-P[l];
27         seg[x].val.f.v[0][1]=Q[l]; seg[x].val.f.v[0][0]=1.-Q[l];
28         seg[x].val.g.v[1][1]=P[l]; seg[x].val.g.v[0][1]=Q[l];
29         return;
30     }
31     int mid=(l+r)>>1;
32     build(ls,l,mid); build(rs,mid+1,r); seg[x].val=seg[ls].val+seg[rs].val;
33 }
34
35 inf que(int x,int L,int R,int l,int r){
36     if (L==l && r==R) return seg[x].val;
37     int mid=(L+R)>>1;
38     if (r<=mid) return que(ls,L,mid,l,r);
39     else if (l>mid) return que(rs,mid+1,R,l,r);
40         else return que(ls,L,mid,l,mid)+que(rs,mid+1,R,mid+1,r);
41 }
42
43 double ask(int l,int r){ inf v=que(1,0,n+1,l+1,r); return v.g.v[S2[l]][S2[r]]/v.f.v[S2[l]][S2[r]]; }
44
45 int main(){
46     freopen("game.in","r",stdin);
47     freopen("game.out","w",stdout);
48     scanf("%d%d",&n,&m); scanf("%s",op); scanf("%lf",&P[1]);
49     rep(i,2,n) scanf("%lf%lf",&P[i],&Q[i]);
50     S1.insert(0); S2[0]=1; S1.insert(n+1); S2[n+1]=0; P[n+1]=Q[n+1]=0.;
51     build(1,0,n+1); ans=ask(0,n+1);
52     while (m--){
53         scanf("%s",op);
54         if (*op==‘a‘){
55             scanf("%d%d",&p,&c); set<int>::iterator nxt=S1.lower_bound(p),lst=nxt; lst--;
56             S2[p]=c; ans-=ask(*lst,*nxt); ans+=ask(*lst,p)+ask(p,*nxt); S1.insert(p);
57         }else{
58             scanf("%d",&p); set<int>::iterator mid=S1.find(p),lst,nxt;
59             lst=nxt=mid; lst--; nxt++; ans-=ask(*lst,p)+ask(p,*nxt); ans+=ask(*lst,*nxt); S1.erase(p);
60         }
61         printf("%.6lf\n",ans);
62     }
63     return 0;
64 }

原文地址:https://www.cnblogs.com/HocRiser/p/8877059.html

时间: 2024-10-17 09:07:05

[CTSC2017]游戏(Bayes定理,线段树)的相关文章

【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都发了一个传话筒. 于

Codeforces Round #FF (Div. 2) E. DZY Loves Fibonacci Numbers(斐波那契的定理+线段树)

/* 充分利用了菲波那切数列的两条定理: ①定义F[1] = a, F[2] = b, F[n] = F[n - 1] + F[n - 2](n≥3). 有F[n] = b * fib[n - 1] + a * fib[n - 2](n≥3),其中fib[i]为斐波那契数列的第 i 项. ②定义F[1] = a, F[2] = b, F[n] = F[n - 1] + F[n - 2](n≥3). 有F[1] + F[2] + -- + F[n] = F[n + 2] - b 这题还有一个事实,

【题解】 AtCoder ARC 076 F - Exhausted? (霍尔定理+线段树)

题面 题目大意: 给你\(m\)张椅子,排成一行,告诉你\(n\)个人,每个人可以坐的座位为\([1,l]\bigcup[r,m]\),为了让所有人坐下,问至少还要加多少张椅子. Solution: 为什么加椅子?我们可以在最左边或最右边一直加直到人人都有座位. 首先这道题目抽象成二分图很简单,然后我们可以只要求解出人与座位的最大匹配是多少,总人数减去即可,但跑二分图最大匹配显然会超时,我们就可以往霍尔定理方面想. 然后你还需要知道一个霍尔定理推论:假设某个人的集合为\(X\),这个集合所对应的

【BZOJ2138】stone Hall定理+线段树

[BZOJ2138]stone Description 话说Nan在海边等人,预计还要等上M分钟.为了打发时间,他玩起了石子.Nan搬来了N堆石子,编号为1到N,每堆包含Ai颗石子.每1分钟,Nan会在编号在[Li,Ri]之间的石堆中挑出任意Ki颗扔向大海(好疼的玩法),如果[Li,Ri]剩下石子不够Ki颗,则取尽量地多.为了保留扔石子的新鲜感,Nan保证任意两个区间[Li,Ri]和[Lj,Rj],不会存在Li<=Lj&Rj<=Ri的情况,即任意两段区间不存在包含关系.可是,如果选择不

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

小 R 和室友小 B 在寝室里玩游戏.他们一共玩了 $n$ 局游戏,每局游戏的结果要么是小 R 获胜,要么是小 B 获胜. 第 $1$ 局游戏小 R 获胜的概率是 $p_1$,小 B 获胜的概率是 $1-p_1$.除了第一局游戏之外,每一局游戏小 R 获胜的概率与上一局游戏小 R 是否获胜有关. 具体来说: 如果第 $i-1\ (1< i\le n)$ 局游戏小 R 获胜,那么第 $i$ 局游戏小 R 获胜的概率为 $p_i$,小 B 获胜的概率为 $1-p_i$. 如果第 $i-1\ (1<

【AtCoder ARC076】F Exhausted? 霍尔定理+线段树

题意 N个人抢M个椅子,M个椅子排成一排 ,第i个人只能坐[1,Li]∪[Ri,M],问最多能坐多少人 $i$人连边向可以坐的椅子构成二分图,题意即是求二分图最大完美匹配,由霍尔定理,答案为$max(|X|-\omega(X))$,$X$为人的集合,$\omega(X)$可以表示为$[1,l] \cup[r,M]$,所以可以枚举$\omega(X)$也就是$(l,r)$,求出最大的$|X|$,也就是满足$L_i\le l \land r \le R_i$的$i$的数量,也就是平面上以$(l,r)

&quot;盛大游戏杯&quot; M 风力观测 (线段树)

题目链接:"盛大游戏杯" M 风力观测 题意: 给你n个数,现在有m个操作. 1 L R V 给[L,R]区间全部加V. 2 X 询问X这个点 历史的绝对值最大是多少. 题解: 对于每个询问,其实我们只需要记录下在这个过程中最大的偏移量和最小的偏移量就行了. 所以直接一个线段树搞一搞就行了. 1 #include<bits/stdc++.h> 2 #define ls l,m,rt<<1 3 #define rs m+1,r,rt<<1|1 4 #d

bzoj 1594: [Usaco2008 Jan]猜数游戏——二分+线段树

Description 为了提高自己低得可怜的智商,奶牛们设计了一个新的猜数游戏,来锻炼她们的逻辑推理能力. 游戏开始前,一头指定的奶牛会在牛棚后面摆N(1 <= N<= 1,000,000)堆干草,每堆有若干捆,并且没有哪两堆中的草一样多.所有草堆排成一条直线,从左到右依次按1..N编号,每堆中草的捆数在1..1,000,000,000之间. 然后,游戏开始.另一头参与游戏的奶牛会问那头摆干草的奶牛 Q(1 <= Q <= 25,000)个问题,问题的格式如下: 编号为Ql..Q

【BZOJ-4515】游戏 李超线段树 + 树链剖分 + 半平面交

4515: [Sdoi2016]游戏 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 304  Solved: 129[Submit][Status][Discuss] Description Alice 和 Bob 在玩一个游戏. 游戏在一棵有 n 个点的树上进行.最初,每个点上都只有一个数字,那个数字是 123456789123456789. 有时,Alice 会选择一条从 s 到 t 的路径,在这条路径上的每一个点上都添加一个数字.对于路径上