题意:有个人从1位置开始走,每次走1歩的概率为p,走两步的概率为1-p,在N个位置上有地雷,问这个人不踩到地雷通过的概率。
思路:可以看出安全走到某一位置的概率f(x)=f(x-1)*p+f(x-2)*(1-p)。类似fibonacci的这么个东西,然后用矩阵快速幂计算到达每个雷的位置的概率和前一个位置的概率。走到最后,结果为安全到达最后一个雷前一个位置的概率×(1-p),也就是要跳过那个雷。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
struct Matrix
{
double mat[2][2];
void Init()
{
mat[0][0]=mat[1][1]=1;
mat[0][1]=mat[1][0]=0;
}
void clear() {memset(mat,0,sizeof(mat));}
};
Matrix operator *(const Matrix &a,const Matrix &b)
{
Matrix c;c.clear();
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;
}
int mines[20];
void cal(int n,double &p1,double &p2,double p)
{
Matrix x,y;
x.Init();y.clear();
y.mat[0][0]=p;y.mat[1][0]=1-p;
y.mat[0][1]=1;
while(n)
{
if(n&1) x=x*y;
y=y*y;
n>>=1;
}
double px=p1*x.mat[0][0]+p2*x.mat[1][0];
double py=p1*x.mat[0][1]+p2*x.mat[1][1];
p1=px;p2=py;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n;
double p;
while(~scanf("%d%lf",&n,&p))
{
for(int i=0;i<n;++i)
scanf("%d",&mines[i]);
sort(mines,mines+n);
double ans=0,p1,p2;
if(mines[0]!=1)
{
p1=1,p2=0;
int now=1;
for(int i=0;i<n;++i)
{
cal(mines[i]-now,p1,p2,p);
p1=0;
now=mines[i];
}
ans=(1-p)*p2;
}
printf("%.7lf\n",ans);
}
return 0;
}