標籤:blog http os io 2014 for
連結:http://acm.hdu.edu.cn/showproblem.php?pid=4870
題意:用兩個帳號去參加一種比賽,初始狀態下兩個帳號都是零分,每次比賽都用分數低的帳號去比賽,有P的機率取勝,對應帳號分數上漲50分,否則對應帳號分數下降100分,問當有一個帳號分數達到1000分時參加比賽次數的數學期望是多少。
思路:比賽期間以為是一道推公式的題,推了半天沒什麼收穫。賽後想了想,看瞭解題報告以後,知道了這種每個分數對應狀態受到兩個狀態以上推得並且不是從後向前推得情況可以用高斯消元來解。狀態0~狀態209分別代表者分數為(0,0),(50,0)...(950,950)到有一個帳號的分數為1000的數學期望。E(X,Y)=p(E(x1,y1)+1)+(1-p)(E(x2,y2)+1),(x1,y1)代表著這次比賽取勝之後兩個帳號的分數,(x2,y2)代表著這次比賽失敗之後兩個帳號的分數。狀態中不用計入狀態(1000,?)是因為除了(1000,950)外其他狀態不會出現。而(1000,950)狀態只與狀態(950,950)有關,並且(950,950)不會從(1000,950)得到,所以210個狀態中沒有狀態是與(1000,?)狀態相關,所以不需要處理。
代碼:
#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <map>#include <cstdlib>#include <queue>#include <stack>#include <vector>#include <ctype.h>#include <algorithm>#include <string>#include <set>#define PI acos(-1.0)#define maxn 210#define INF 0x7fffffff#define eps 1e-8#define MOD 1000000009typedef long long LL;typedef unsigned long long ULL;using namespace std;double a[220][220],b[220];int all[25];double gauss_elimination(int n){ int i,j,k,row; double maxp,t; for(k=0; k<n; k++) { for(maxp=0,i=k; i<n; i++) if (fabs(a[i][k])>eps) { maxp=a[row=i][k]; break; } if(fabs(maxp)<eps) return 0; if(row!=k) { for(j=k; j<n; j++) swap(a[k][j],a[row][j]); swap(b[k],b[row]); } for (int j = 0; j < n; j++) { if (k == j) continue; if (fabs(a[j][k]) > eps) { double x = a[j][k] / a[k][k]; for (int i = k; i < n; i++) { a[j][i] -= a[k][i] * x; } b[j] -=b[k]*x; } } } return 1;}int init(){ all[0]=0; for(int i=1; i<=21; i++) { all[i]=all[i-1]+i; } return 0;}int main(){ double p; init(); while(~scanf("%lf",&p)) { memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); for(int i=0; i<20; i++) { for(int j=0; j<=i; j++) { a[all[i]+j][all[i]+j]+=1; b[all[i]+j]+=1; a[all[i]+j][all[i]+max(j-2,0)]+=(p-1); if(j+1<=i) a[all[i]+j][all[i]+j+1]+=(-p); else { if(i==19&&j==19) continue; else a[all[i]+j][all[j+1]+i]+=(-p); } } } gauss_elimination(210); printf("%.6lf\n",b[0]/a[0][0]); } return 0;}