题意:在坐标范围在[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;
}