[Non] 踩地雷I

[Non] 踩地雷I

大意

一条路上有 \(N\) 个地雷。你站在起点 \(1\) 的位置,每次有概率 \(p\) 走 \(1\) 步,有概率 \(1 - p\) 走 \(2\) 步。给出 \(N\),\(p\) 与 \(N\) 个雷的坐标 \(X\):,请你求出你踩不到地雷的概率是多少。

思路

首先我们考虑一个问题,\(N\) 很小,只有 \(10\) 左右,但是范围为 \(10^8\),我们可以考虑分段处理。

如果是定义 \(P[i]\) 为踩不到第 \(i\) 个位置的概率,我们定义 \(dp[i]\) 是踩到第 \(i\) 个地雷的概率,那么显然有 \(P[i] = 1 - dp[i]\),那么我们的答案即为 \(\prod_{i = 1}^{n} P[x[i] - x[i - 1] - 1]\)。

关于 \(dp\),我们有 \(dp[i] = dp[i - 1] \times p + dp[i - 2] \times (1 - p)\),发现这个递推式很美丽,类似于斐波那契,所以我们考虑写出矩阵转移方程:

\[\begin{bmatrix} dp[n] \\ dp[n-1] \end{bmatrix} = \begin{bmatrix} p & 1-p \\ 1 & 0 \end{bmatrix}^{n-1} \begin{bmatrix} dp[1] \\ dp[0] \end{bmatrix} \]

然后我们就可以矩阵快速幂计算。

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100 + 10;
int mod, a[100], n;
typedef long long ll;
struct Matrix {
    int n, m;
    double a[maxn][maxn];
};
Matrix mul(Matrix &a, Matrix &b) {
    Matrix res = {a.n, b.m};
    for (int i = 0; i < a.n; i++)
        for (int j = 0; j < b.m; j++)
            for (int k = 0; k < a.m; k++)
                res.a[i][j] += a.a[i][k] * b.a[k][j];
    return res;
}
Matrix Pow(Matrix base, ll n) {
    Matrix res = {base.n, base.n};
    for (int i = 0; i < base.n; i++) res.a[i][i] = 1;
    while (n) {
        if (n & 1) res = mul(res, base);
        base = mul(base, base);
        n >>= 1;
    }
    return res;
}
int main() {
    double p;
    while (cin >> n >> p) {
        Matrix base = {2, 2};
        base.a[0][0] = 0, base.a[0][1]  = 1 - p;
        base.a[1][0] = 1, base.a[1][1] = p;
        for (int i = 1; i <= n; i++) cin >> a[i];
        sort(a + 1, a + n + 1);
        double res = 1;
        for (int i = 1; i <= n; i++) {
            if (a[i] == a[i - 1]) continue;
            Matrix ans = {1, 2};
            ans.a[0][1] = 1;
            Matrix bp = Pow(base, a[i] - a[i - 1] - 1);
            ans = mul(ans, bp);
            res *= (1 - ans.a[0][1]);
        }
        printf("%.7lf\n", res);
    }
    return 0;
}
posted @ 2026-01-17 12:23  To_Carpe_Diem  阅读(15)  评论(0)    收藏  举报