[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;
}
本文来自一名高中生,作者:To_Carpe_Diem

浙公网安备 33010602011771号