D T4 飞行棋

题面

https://ac.nowcoder.com/acm/contest/7612/D

思路

数学期望题。

维护一个 数组, 代表从 的期望回合数。

通过列多元方程组可以得到 。 (这点数学基本功要有吧······)

然后就是一个递推的过程,要注意抛出 时即 时无需计算回合数,剩下的均要一个回合。

细节看代码注释

代码

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <vector>
#include <set>
#include <map>

using std::cin;using std::cout;using std::cerr;using std::endl;

#define rep(i,a,b) for(int i = a;i <= b;++i)
#define per(i,a,b) for(int i = a;i >= b;--i)

const int mmax = 1e5;

int T,n;
double d,dp[mmax + 10],sum[mmax + 10];

int main(){

    std::ios::sync_with_stdio(0);
    cin.tie(0);

    cin>>T;

    while(T--){
        cin>>n>>d;
        int t = d;

        rep(i,1,t - 1){
            dp[i] = t - 1;
            sum[i] = sum[i - 1] + dp[i]; //前缀和维护,降低复杂度
        }

        dp[t] = dp[t - 1]  + 1 / d;
        sum[t] = sum[t - 1] + dp[t];

        rep(i,d + 1,n){
            dp[i] = (sum[i - 1] - sum[i - t] + d - 1) / d + dp[i - t] / t;
            //抛出的k的概率为 1 / d,
            //k < d 时到达终点的期望贡献为(1 + dp[i - k]) / d。
            //k = d 时到达终点的期望贡献为dp[i - k]。
            sum[i] = sum[i - 1] + dp[i];
        }

        printf("%.2f\n",dp[n]);    
    }

    return 0;
}