题意

众所周知, y a n g 12138 yang12138 yang12138是一名 p u p i l pupil pupil。 他在 c o d e f i r e codefire codefire上注册了两个帐户。这两个帐户最初都处于0级,并且该级别最多为 n n n。每次他赢了,等级会增加1,但如果他输了,级别就不会更改。 当在级别 i i i使用帐户时, y a n g 12138 yang12138 yang12138的获胜概率是 p i p_i pi。达到 n n n级的人在 c o d e f i r e codefire codefire中被称为 G r a n d M a s t e r GrandMaster GrandMaster y a n g 12138 yang12138 yang12138有作为一名 G r a n d M a s t e GrandMaste GrandMaster的梦想,所以他正在努力。 他的策略如下:
1.初始有两个帐号, y a n g 12138 yang12138 yang12138会随机选择一个账户参加比赛。
2.假设他目前正在使用账户A,如果他赢了,他继续使用帐户A参加比赛。 否则他将使用其他帐户。
3.当他的任何账户达到 n n n级时,立即停止,因为 y a n g 12138 yang12138 yang12138已成为 y a n g 12138 yang12138 yang12138。在每个级别获得 y a n g 12138 yang12138 yang12138的概率。

你作为一个 G r a n d M a s t e r GrandMaster GrandMaster,请计算 y a n g 12138 yang12138 yang12138成为一个 G r a n d M a s t e r GrandMaster GrandMaster的比赛次数的期望。

做法

考虑期望 d p dp dp.

d p [ i ] [ j ] [ 0 / 1 ] dp[i][j][0/1] dp[i][j][0/1]表示第一个帐号级别为 i i i,第二个帐号级别为 j j j,且当前使用的是 0 / 1 0/1 0/1的帐号的期望.

转移方程:

d p [ i ] [ j ] [ 0 ] = d p [ i + 1 ] [ j ] [ 0 ] p i + d p [ i ] [ j ] [ 1 ] ( 1 p i ) + 1 dp[i][j][0] = dp[i+1][j][0]*p_i + dp[i][j][1] * (1-p_i)+1 dp[i][j][0]=dp[i+1][j][0]pi+dp[i][j][1](1pi)+1

d p [ i ] [ j ] [ 1 ] = d p [ i ] [ j + 1 ] [ 1 ] p j + d p [ i ] [ j ] [ 0 ] ( 1 p j ) + 1 dp[i][j][1]=dp[i][j+1][1]*p_j+dp[i][j][0]*(1-p_j) + 1 dp[i][j][1]=dp[i][j+1][1]pj+dp[i][j][0](1pj)+1

联立两式消元即可.

代码

#include<bits/stdc++.h>
using namespace std;
typedef double db;
const int N = 307;
db p[N], dp[N][N][2];

int main() {
#ifdef local
    freopen("in.txt", "r", stdin);
#endif
    int T; scanf("%d", &T);
    while(T--) {
        int n; scanf("%d", &n);
        for(int i = 0; i < n; i++) scanf("%lf", p + i);
        for(int k = 0; k < 2; k++)
            for(int i = 0; i <= n; i++)
                dp[i][n][k] = dp[n][i][k] = 0;
        for(int i = n-1; ~i; i--) {
            for(int j = n-1; ~j; j--) {
                dp[i][j][0] = (dp[i+1][j][0]*p[i]+dp[i][j+1][1]*p[j]*(1-p[i])+2-p[i])
                        /(p[i]+p[j]-p[i]*p[j]);
                dp[i][j][1] = (dp[i][j+1][1]*p[j]+dp[i+1][j][0]*p[i]*(1-p[j])+2-p[j])
                        /(p[i]+p[j]-p[i]*p[j]);
            }
        }

        printf("%.4f\n", dp[0][0][0]);
    }
    return 0;
}