概率期望学习笔记
概率期望笔记
- 很抽象的一个东西,经常与dp,高斯消元,组合扔在一起
一些具体的概念可以参见高中数学课本
概率
我们用\(P(A)\)表示事件\(A\)发生的概率
一.性质
- \(P(\varnothing) = 0\)
- 可加性:当\(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)\)
- \(P(A)=1-P(\bar A)\)
- 当事件\(A\)包含于事件\(B\)时,\(P(B-A)=P(B)-P(A)\)
- 对于两个事件\(A,B\),\(P(B-A)=P(B)-P(A\cap B)\)
- 对于两个事件\(A,B\),\(P(A+B)=P(A)+P(B)-P(A\cap B)\)
二.例题
-
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));
-
\(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);
-
\(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);
-
\(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\)
-
\(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); } }
-
\(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));
-
\(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]);
-
\(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);
-
\(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); }
-
\(solution:\)
同7
-
\(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\)
-
\(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\)
本文来自博客园,作者:CuFeO4,转载请注明原文链接:https://www.cnblogs.com/hzoi-Cu/p/18272504