题目链接 2014 多校1 Problem J
题意 现在有两个账号,初始$rating$都为$0$,现在每次打分比较低的那个,如果进前$200$那么就涨$50$分,否则跌$100$分。
每一次打进前$200$的概率为$p$,且每一次竞赛是相互独立的。求当一个号打到$1000$分时已经打的期望场数。
把$1000$变成$20$,并且分析出所有有效的状态。
有效的状态一共$211$个。
$(0, 0)$
$(1, 0), (1, 1)$
$(2, 0), (2, 1), (2, 2)$
......
$(19, 0), (19, 1), (19, 2), ..., (19, 19)$
再加一个$(20, 19)$,这是目标状态。
设$f(x, y)$为$(x, y)$状态时所需要到达目标的期望场数。
显然$f(19, 20) = 0$
设$(x, y)$赢了之后状态为$(x1, y1)$, 输了之后状态为$(x2, y2)$
那么$f(x, y) = p*f(x1, y1) + (1-p)*f(x2, y2) + 1$
注意状态$(0, 0)$输了之后还是$(0, 0)$
那么建立211个方程组,高斯消元求解即可。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) typedef long long LL; const int N = 235; const double eps = 1e-12; double a[N][N], x[N], p; int equ, var; int c[N][N]; int cnt; int y; void Gauss(){ int row, col, max_r; row = col = 0; while (row < equ && col < var){ max_r = row; rep(i, row + 1, equ - 1) if (fabs(a[i][col]) - fabs(a[max_r][col]) > eps) max_r = i; if (max_r != row) rep(j, col, var) swap(a[row][j], a[max_r][j]); if (fabs(a[row][col]) < eps){ col++; continue; } rep(i, row + 1, equ - 1){ if (fabs(a[i][col]) > eps){ double t = a[i][col] / a[row][col]; a[i][col] = 0.0; rep(j, col + 1, var) a[i][j] -= a[row][j] * t; } } row++; col++; } dec(i, equ - 1, 0){ if (fabs(a[i][i]) < eps) continue; double tmp = a[i][var]; rep(j, i + 1, var - 1) tmp -= a[i][j] * x[j]; x[i] = tmp / a[i][i]; } } int main(){ cnt = 0; for (int i = 0; i <= 22; ++i){ for (int j = 0; j <= 22; ++j){ c[i][j] = -1e9; } } rep(i, 0, 19) rep(j, 0, i) c[i][j] = cnt++; c[20][19] = cnt++; equ = var = cnt; while (~scanf("%lf", &p)){ memset(a, 0, sizeof a); rep(i, 0, 19){ rep(j, 0, i - 1){ y = c[i][j]; a[y][y] = 1; a[y][211] = 1; a[y][c[i][max(0, j - 2)]] -= (1 - p); a[y][c[i][j + 1]] -= p; } y = c[i][i]; a[y][y] = 1; a[y][211] = 1; a[y][c[i][max(0, i - 2)]] -= (1 - p); a[y][c[i + 1][i]] -= p; } a[210][210] = 1; Gauss(); printf("%.6lf ", x[0]); } return 0; }