1.000000 0.814700
39.000000 82.181160
一场比赛,赢了可以得50分,输了扣100分,分数会超过1000和不会小于0.有个人用2个账号,始终用分数低的号比赛。已知赢一场比赛的概率为p求打到1000分的场数的期望值。
1、可以用高斯消元,
令E(X,Y)为账号分数为x,y打到1000的数学期望。则有:
E(X,Y)=PE(X1,Y1)+(1-P)E(X2,Y2)+1,X1,Y1是XY分数赢了的分数,X2,Y2对应是输了的分数,假设X>=Y,每次比赛用Y的账号,就会有210条方程,用mark数组标记XY分数对应的系数的索引。
代码:
#include <iostream> #include <cmath> #include <stdio.h> #include <algorithm> #include <ctime> #include <vector> #include <cstring> #include <map> #include <string> #include <queue> using namespace std; #define LL long long #define ULL unsigned long long //#define REP(i,n) for(int i=0;i<n;++i) #define REP(i,a,b) for(int i=a;i<=b;++i) #define INFLL (1LL)<<62 #define mset(a) memset(a,0,sizeof a) #define FR(a) freopen(a,"r",stdin) #define FW(a) freopen(a,"w",stdout) #define PI 3.141592654 const LL MOD = 1000000007; const int maxn=222; const double eps=1e-9; double a[maxn][maxn]; int mark[25][25]; int cnt; double gauss() { int m=211; int n=210; for(int i=0;i<n;i++) { int k=i; for(;k<n;++k) if(fabs(a[k][i])>eps) break; if(i!=k) for(int j=0;j<=n;++j) swap(a[i][j],a[k][j]); for(int j=0;j<n;++j) { if(i==j) continue; if(fabs(a[j][i])<eps) continue; double x=a[j][i]/a[i][i]; for(k=i;k<m;++k) a[j][k]-=a[i][k]*x; } } return a[0][n]/a[0][0]; } void makeMat(double p) { mset(a); int m=211; int x=0,y=0; for(y=0;y<20;++y){ for(x=0;x<y;++x) { int temp=mark[y][x]; a[temp][temp]=1; a[temp][m-1]=1; int temp2=mark[y][max(0,x-2)]; a[temp][temp2]-=1-p; temp2=mark[y][x+1]; a[temp][temp2]-=p; } int t=mark[y][y]; a[t][t]=1; a[t][m-1]=1; int tt=mark[y][max(0,x-2)]; a[t][tt]-=1-p; tt=mark[x+1][x]; a[t][tt]-=p; } } int main() { double p; cnt=0; mset(mark); REP(i,0,20) REP(j,0,i) mark[i][j]=cnt++; while (cin>>p) { makeMat(p); printf("%.6lf\n",gauss()); } }
2、用dp
首先离散化,因为每场比赛分数的变化都是50的倍数,令每场赢了得1分,输了扣2分。
dp[i]表示单场比赛从i分数提高到i+1的分数的期望值,
则有:dp[i]=p+(1-p)(dp[i-2]+dp[i-1]+dp[i]+1)
==>dp[i]=1/p+(1-p)/p*(dp[i-2]+dp[i-1]);dp[0]=1/p,dp[1]=1/p/p;
用ans[i][i]表示两个账号分数从0打到ii的期望,对于账号分数的上升,他们是交错上升的,意思是当他们分数一样的时候,前面的赢一分,当前面的赢了一分之后,下一场就后面的赢,所以只需要维护ans[i+1][i] 和ans[i+1][i+1],且
ans[i+1][i]=ans[i][i]+dp[i],ans[i+1][i+1]=ans[i+1][i]+dp[i],
代码:
#include <iostream> #include <cmath> #include <stdio.h> using namespace std; double dp[22]; double ans[22][22]; int main() { double p; while (cin>>p) { dp[0]=1/p; dp[1]=1/p/p; for(int i=2;i<20;++i) dp[i] = 1+(1-p)/p*(dp[i-2]+dp[i-1]+1); ans[0][0]=0; for (int i=0;i<20;++i) { ans[i+1][i]=ans[i][i]+dp[i]; ans[i+1][i+1]=ans[i+1][i]+dp[i]; } printf("%.6lf\n",ans[20][19]); } }