概率期望学习笔记

概率期望笔记

  • 很抽象的一个东西,经常与dp,高斯消元,组合扔在一起

一些具体的概念可以参见高中数学课本

概率

我们用\(P(A)\)表示事件\(A\)发生的概率

一.性质

  1. \(P(\varnothing) = 0\)
  2. 可加性:当\(A_1,A_2,...,A_n\)两两互斥,则有\(P(A_1\cup A_2 \cup ... \cup A_n) = P(A_1)+P(A_2)+...+P(A_n)\)
  3. \(P(A)=1-P(\bar A)\)
  4. 当事件\(A\)包含于事件\(B\)时,\(P(B-A)=P(B)-P(A)\)
  5. 对于两个事件\(A,B\),\(P(B-A)=P(B)-P(A\cap B)\)
  6. 对于两个事件\(A,B\),\(P(A+B)=P(A)+P(B)-P(A\cap B)\)

二.例题

  1. Little Pony and Expected Maximum

    \(solution:\)

    则如果投了\(n\)次,最大的点数为\(k\)
    \(n\)次投掷的点数都在\(1\sim k\)中,共有\(k^n\)种情况
    \(n\)次投掷的点数都在\(1\sim k-1\)中,共有\((k-1)^n\)种情况
    则最大值为\(k\)时,共有\(k^n-(k-1)^n\)种情况
    所以期望\(ans=\frac{\sum_{i=1}^{m}i*(i^n-(i-1)^n)}{m^n}=\sum_{i=1}^{m}i*((\frac{i}{m})^n-(\frac{i-1}{m})^n)\)

    \(code:\)

    点击查看代码
    for(int i = 1;i <= m; ++i)
        ans += i*(pow(1.0*i/m,n)-pow(1.0*(i-1)/m,n));
    
  2. 红包发红包

    \(solution:\)

    对于第1个人来说,还剩\(w\)元,期望抢到\(\frac{w}{2}\)

    对于第2个人来说,还剩\(\frac{w}{2}\)元,期望抢到\(\frac{w}{4}\)

    ……

    对于第k个人来说,还剩\(\frac{w}{2^{k-1}}\)元,期望抢到\(\frac{w}{2^k}\)

    \(code:\)

    点击查看代码
    write(1ll*w*power(power(2,k,mod),mod-2,mod)%mod);
    
  3. 单选错位

    \(solution:\)

    \(i\)道题做对的可能性为\(\frac{min(a[i],a[i-1])}{a[i]*a[i-1]}\)

    可以化简为\(\frac{1}{max(a[i],a[i-1])}\)

    注意i=1时特判

    \(code:\)

    点击查看代码
    read(n,A,B,C,a[1]);
    for(int i = 2;i <= n; ++i) a[i] = (1ll*a[i-1]*A+B)%100000001;
    for(int i = 1;i <= n; ++i) a[i] = a[i]%C+1;
    double ans = 0;
    ans += 1.0/max(a[1],a[n]);
    for(int i = 2;i <= n; ++i) ans += 1.0/max(a[i],a[i-1]);
    printf("%.3lf",ans);
    
  4. [SHOI2002]百事世界杯之旅

    \(solution:\)

    \(f_k\)为已经有了\(k\)

    \(f_{k+1}=f_k+n*\frac{1}{n-k}\)

    所以\(f_n = n*\sum_{i=1}^n\frac{1}{i}\)

    \(no\quad code\)

  5. 绿豆蛙的归宿

    \(solution:\)

    \(f_i\)为从\(i\)\(n\)的期望,有

    \[f_x = \sum_{i=1}^{oud[x]}(f_y+edge[i])/oud[x] \]

    目标\(f_1\)

    \(code:\)

    点击查看代码
    //为了方便,这里建的是反图,in1为原图的出度,in2为反图的出度
    queue<int> q;q.push(n);
    while(q.size()){
        int x=q.front();q.pop();
        for(int i=head[x];i;i=edge[i].next){
            int y=edge[i].to;
            f[y]+=1.0*(f[x]+edge[i].w)/in1[y];
            --in2[y];
            if(!in2[y]) q.push(y);
        }
    }
    
  6. 聪聪和可可

    \(solution:\)
    猫可以走\(1\)\(2\)步;老鼠可能不动;猫一定向离着老鼠近的地方走。

    先预处理出当猫在\(i\)处,老鼠在\(j\)处时,猫下一步要走的位置\(nxt[i][j]\)
    这个跑\(n\)\(spfa\)\(dijkstra(priority\_queue)\)即可
    但bfs貌似更好

    \(f[i][j]\)表示猫在\(i\),老鼠在\(j\)处时,所需的期望步数。

    \[f[i][j] = \begin{cases} 0,&i=j\\ 1,&\text{猫走一步或两步即可到达}\\ sum(f[nxt[nxt[i][j]][j]]/(oud[j]+1))+1 \end{cases}\]

    递归形式,显然记忆化搜索。

    目标:\(f[s][t]\)

    \(code:\)

    点此查看代码
    const int N = 1e3+10;
    struct EDGE{int to,next;}edge[N<<1];
    int head[N],cnt;
    inline void add(int u,int v){
        edge[++cnt] = {v,head[u]};
        head[u] = cnt;
    }
    int nxt[N][N],dist[N][N],n,m,s,t,d[N];
    double f[N][N];
    bitset<N> vis;
    inline void bfs(){
        memset(dist,0x3f,sizeof dist);
        memset(nxt,0x3f,sizeof nxt);
        for(int s = 1;s <= n; ++s){
            vis.reset();
            dist[s][s] = 0;
            queue<int> q;q.push(s);
            vis[s] = true;
            while(q.size()){
                int x = q.front();q.pop();vis[x] = false;
                for(int i = head[x]; i;i = edge[i].next){
                    int y = edge[i].to;
                    if(dist[s][y] > dist[s][x] + 1){
                        dist[s][y] = dist[s][x] +1;
                        if(!vis[y]){
                            vis[y] = true;
                            q.push(y);
                        }
                    }
                }
            }
        }
        for(int x = 1;x <= n; ++x){
            for(int i = head[x]; i;i = edge[i].next){
                int k = edge[i].to;
                for(int y = 1;y <= n; ++y){
                    if(dist[x][y] == dist[k][y] + 1)
                        nxt[x][y] = min(nxt[x][y],k);
                }
            }
        }
    }
    double dp(int i,int j){
        if(f[i][j] != -1.0) return f[i][j];
        if(i == j) return f[i][j] = 0.0;
        if(nxt[i][j] == j || nxt[nxt[i][j]][j] == j) return f[i][j] = 1.0;
        f[i][j] = 0.0;
        for(int k = head[j]; k;k = edge[k].next){
            int l = edge[k].to;
            f[i][j] += dp(nxt[nxt[i][j]][j],l);
        }
        f[i][j] = (f[i][j]+dp(nxt[nxt[i][j]][j],j))/(d[j]+1)+1;
        return f[i][j];
    }
    //main
    read(n,m,s,t);
    for(int i = 1,u,v;i <= m; ++i){
        read(u,v);
        add(u,v);add(v,u);
        d[u]++;d[v]++;
    }
    for(int i = 1;i <= n; ++i) for(int j = 1;j <= n; ++j) f[i][j] = -1.0;
    bfs();
    printf("%.3lf",dp(s,t));
    
  7. OSU!

    \(solution:\)

    \((x+1)^3 = x^3+3x^2+3x+1\)

    \((x+1)^2 = x^2+2x+1\)

    所以记录一个\(x^2\)的期望和一个\(x\)的期望即可

    \(code:\)

    点此查看代码
    read(n);
    for(int i = 1;i <= n; ++i) read(p[i]);
    for(int i = 1;i <= n; ++i){
        x1[i] = (x1[i-1]+1)*p[i];
        x2[i] = (x2[i-1]+2*x1[i-1]+1)*p[i];
        ans[i] = ans[i-1]+(3*x2[i-1]+3*x1[i-1]+1)*p[i];
    }
    printf("%.1lf",ans[n]);
    
  8. bzoj1419 Red is Good

    \(solution:\)

    \(f[i][j]\)为已经拿了\(i\)张红牌,\(j\)张黑牌的期望钱数

    \[f[i][j]= \begin{cases} 0,&i==0\\ i,&j==0\\ (f[i-1][j]+1)*i/(i+j)+(f[i][j-1]+1)*j/(i+j),&other\quad cases \end{cases}\]

    \(code:\)

    点此查看代码
    cin>>r>>b;
    for(int i = 0;i <= r; ++i){
        for(int j = 0;j <= b; ++j){
            if(i == 0) {f[i&1][j] = 0.0;continue;}
            if(j == 0) {f[i&1][j] = f[(i-1)&1][j]+1.0;continue;}
            f[i&1][j] = max(0.0,1.0*(f[(i-1)&1][j]+1.0)*i/(i+j)+1.0*(f[i&1][j-1]-1.0)*j/(i+j));
        }
    }
    printf("%.6lf",f[r&1][b]-0.0000005);
    
  9. 守卫者的挑战

    \(solution:\)

    当前背包容量可能为负数(背包装满了且碎片有剩余),且\(-n\le\)容量\(\le n\)

    所以我们将容量统一加上\(n\)

    对于容量大于等于\(n\)的(一定能装完),我们认为其等价于容量为n

    \(f_{i,j,k}\)为第\(i\)个挑战,赢了\(j\)次,当前背包容量为\(k\)时的概率

    \[f_{i,j,k}=f_{i-1,j-1,k-a[i]}*p_i+f_{i-1,j,k}*(1-p_i) \]

    \(code:\)

    点此查看代码
    #include<bits/stdc++.h>
    #include<bits/extc++.h>
    using namespace __gnu_pbds;
    using namespace __gnu_cxx;
    using namespace std;
    #define infile(x) freopen(x,"r",stdin)
    #define outfile(x) freopen(x,"w",stdout)
    #define errfile(x) freopen(x,"w",stderr)
    using ll=long long;using ull=unsigned long long;
    char *p1,*p2,buf[1<<20];
    #define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
    #ifdef linux
    #define pc putchar_unlocked
    #else
    #define pc putchar
    #endif
    namespace IO{
        template<typename T>inline bool read(T &x){x=0;char s=gc();bool f=true;for(;(s<'0'||'9'<s);s=gc()) {if(s=='-') f=false;if(s==EOF)return false;}for(;'0'<=s&&s<='9';s=gc()) x=(x<<1)+(x<<3)+(s^48);if(!f) x=~x+1;return true;}
        inline bool read(double &x){x=0.0;char s=gc();bool f=true;for(;(s<'0'||'9'<s);s=gc()) {if(s=='-') f=false;if(s==EOF)return false;}for(;'0'<=s&&s<='9';s=gc()) x=(x*10)+(s^48);if(s!='.'){return true;}double res=0.1;s=gc();for(;'0'<=s&&s<='9';res/=10,s=gc()) x+=(s^48)*res;x=f?x:-x;return true;}
        inline bool read(long double &x){x=0.0;char s=gc();bool f=true;for(;(s<'0'||'9'<s);s=gc()) {if(s=='-') f=false;if(s==EOF)return false;}for(;'0'<=s&&s<='9';s=gc()) x=(x*10)+(s^48);if(s!='.'){return true;}double res=0.1;s=gc();for(;'0'<=s&&s<='9';res/=10,s=gc()) x+=(s^48)*res;x=f?x:-x;return true;}
        inline bool read(float &x){x=0.0;char s=gc();bool f=true;for(;(s<'0'||'9'<s);s=gc()) {if(s=='-') f=false;if(s==EOF)return false;}for(;'0'<=s&&s<='9';s=gc()) x=(x*10)+(s^48);if(s!='.'){return true;}double res=0.1;s=gc();for(;'0'<=s&&s<='9';res/=10,s=gc()) x+=(s^48)*res;x=f?x:-x;return true;}
        inline bool read(string &str){string ().swap(str);char s=gc();for(;s==' '||s=='\n';s=gc());if(s==EOF) return false; for(;s!=' '&&s!='\n'&&s!=EOF;s=gc())str.push_back(s);return true;}
        inline bool read_line(string &str){string ().swap(str);char s=gc();for(;s==' '||s=='\n';s=gc());if(s==EOF) return false;for(;s!='\n'&&s!=EOF;s=gc()){str.push_back(s);}return true;}
        inline bool read_line(char *str){int len=0;char s=gc();for(;s==' '||s=='\n';s=gc());if(s==EOF) return false;for(;s!='\n'&&s!=EOF;s=gc()){str[len]=s;len++;}str[len]='\0';return true;}
        inline bool read(char &s){char x=gc();for(;x==' '||x=='\n';x=gc());if(x==EOF||x==' '||x=='\n')return false;s=x;return true;}
        inline bool read(char *s){int len=0;char x=gc();for(;x==' '||x=='\n';x=gc());if(x==EOF)return false;for(;x!=' '&&x!='\n'&&x!=EOF;x=gc())s[len++]=x;s[len]='\0';return true;}
        template<class T,class... Args> inline bool read(T &x,Args&... args){return (read(x)&&read(args...));}
        template<class T>inline void write(T x){static T st[45];int top=0;if(x<0)x=~x+1,pc('-');do{st[top++]=x%10;}while(x/=10);while(top)pc(st[--top]^48);}
        inline void write(char x){pc(x);}
        inline void write(string s){for(int i=0;s[i];++i) pc(s[i]);}
        inline void write(char *s){int len=strlen(s);for(int i=0;i<len;++i) pc(s[i]);}
        inline void write(const char *s){int len=strlen(s);for(int i=0;i<len;++i) pc(s[i]);}
        template<class T,class... Args> inline void write(T x,Args... args){write(x);write(args...);}
    }using namespace IO;
    const int N = 210;
    int n,l,k,a[N];
    double p[N],f[N][N][N<<1];
    signed main(){
        #ifndef ONLINE_JUDGE
            infile("in.in");outfile("out.out");
        #else
        #endif
        read(n,l,k);k = min(k,n);
        for(int i = 1;i <= n; ++i) read(p[i]),p[i] /= 100.0;
        for(int i = 1;i <= n; ++i) read(a[i]),a[i] = min(a[i],n);
        f[0][0][k+n] = 1;
        for(int i = 1;i <= n; ++i){
            for(int j = 0;j <= i; ++j){
                for(int k = 0;k <= 400; ++k){
                    f[i][j][k] = f[i-1][j][k]*(1-p[i]);
                    if(j != 0) f[i][j][k] += f[i-1][j-1][max(k-a[i],0)]*p[i];
                }
            }
        }
        double ans = 0;
        for(int i = l;i <= n; ++i){
            for(int j = n;j <= 400; ++j){
                ans += f[n][i][j];
            }
        }
        printf("%.6lf",ans);
    }
    
  10. WJMZBMR打osu!/Easy

    \(solution:\)

    同7

  11. 单选错位

    \(solution:\)

    假设第\(i\)道题目的选项为\(a[i]\),则做对这道题的概率为\(\frac{min(a[i],a[i-1])}{a[i]*a[i-1]}\),即\(\frac{1}{max(a[i-1],a[i])}\)

    \(no\quad code\)

  12. 列队春游

    \(solution:\)

    设身高\(<i\)的人共有\(s\)个,将一个比\(i\)矮的人与\(i\)捆绑,有\(s\)种方案。

    将剩下的\(s-1\)个人在\(n\)个位置中放,有\(A_{n}^{s-1}\)种方案。

    再将剩下的\(n-s\)个人随便排,有\((n-s)!\)种方案

    共有\(s\times A_{n}^{s-1}\times (n-s)!\)种方案

    视野加一的概率为\(\frac{s\times A_{n}^{s-1}\times (n-s)!}{n!}\)

    期望为\(\frac{s\times A_{n}^{s-1}\times (n-s)!}{n!}+1\)

    展开!

    \[ans = \frac{s\times A_{n}^{s-1}\times (n-s)!}{n!}+1 \]

    \[\quad\qquad=\frac{s\times(n-s)!\times\frac{n!}{(n-s+1)!}}{n!}+1 \]

    \[=\frac{s\times (n-s)!}{(n-s+1)!}+1 \]

    \[=\frac{s}{n-s+1}+1 \]

    \(code:\)

    点此查看代码
    read(n);
    for(int i = 1,x;i <= n; ++i) read(x),h[x]++;
    int s = 0;
    double ans = 0;
    for(int i = 1;i <= 1000; ++i){
        if(!h[i]) continue;
        ans += 1.0*(n+1)/(n-s+1)*h[i];
        s += h[i];
    }
    printf("%.2lf",ans);
    

    \(to\quad be\quad continued\)

posted @ 2024-06-30 07:53  CuFeO4  阅读(14)  评论(0编辑  收藏  举报