题意:在坐标范围在[1,100000000]内有10个mine,有一个人从1出发,有p的概率向前走一步,1-p的概率向前走两步,问该人能顺利通过不踩到一个mine的概率是多少。
题解:因为人只能向前走一步或者两步,所以最后人到达pos[n]+1位置的概率即为答案(如果可以到达,否则为0),想到dp[i]表示该人到达坐标为 i 的位置的概率,
即dp[i] = dp[i-1] * p + dp[i-2] * (1 - p);但是坐标范围很大,考虑矩阵快速幂加速,因为如果该地方有mine则概率为0,所以需要在每两个mine之间进行一次矩阵快速
幂即可。每次都是[ans , 0] * [p , 1.0 , 1-p , 0]矩阵相乘。
Sure原创,转载请注明出处。
#include <iostream> #include <cstdio> #include <memory.h> #include <algorithm> using namespace std; const double eps = 1e-8; const int maxn = 12; struct matrix { double mat[2][2]; void clear() { mat[0][1] = mat[1][0] = 0.0; mat[0][0] = mat[1][1] = 1.0; return; } }tran,res; int pos[maxn]; int n; double p; void read() { for(int i=0;i<n;i++) { scanf("%d",&pos[i]); } sort(pos,pos+n); return; } void init() { tran.mat[0][0] = p; tran.mat[0][1] = 1.0; tran.mat[1][0] = 1.0 - p; tran.mat[1][1] = 0; return; } inline matrix mul(matrix a , matrix b) { matrix c; c.mat[0][0] = c.mat[0][1] = c.mat[1][0] = c.mat[1][1] = 0.0; for(int k=0;k<2;k++) { for(int i=0;i<2;i++) { for(int j=0;j<2;j++) { c.mat[i][j] += a.mat[i][k] * b.mat[k][j]; } } } return c; } void powmi(int x) { matrix tmp = tran; res.clear(); while(x) { if(x & 1) { res = mul(res , tmp); } tmp = mul(tmp , tmp); x >>= 1; } return; } bool check() { for(int i=0;i<n-1;i++) { if(pos[i+1] - pos[i] < 2) return false; } return true; } void solve() { if(pos[0] == 1 || check() == false) { puts("0.0000000"); return; } double ans = 1.0; int step = pos[0] - 2; for(int i=0;i<n;i++) { powmi(step); ans *= res.mat[0][0]; ans *= 1.0 - p; if(i < n-1) step = pos[i+1] - pos[i] - 2; } printf("%.7f\n",ans); return; } int main() { while(~scanf("%d %lf",&n,&p)) { read(); init(); solve(); } return 0; }