tag:概率dp
思路:对于当前的位置i,p的概率来自i-1,(1-p)的概率来自 i-2 的位置,但是有雷的位置,概率为0
设dp[i]表示走到i位置的概率,dp[0]=0,dp[1]=1,dp[i]=p*dp[i-1]+(1-p)*dp[i-2] 有雷的地方 dp[i]=0
由于范围比较大,但是雷的个数只有10个,所以讨论到达每一个雷的下一个位置即可,其间用矩阵快速幂解决
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
struct Matrix
{
double m[3][3];
}E,D;
double p;
int mines[11];
void init()
{
for(int i=1;i<=2;i++)
for(int j=1;j<=2;j++)
E.m[i][j]=(i==j);
D.m[1][1]=p;
D.m[1][2]=1-p;
D.m[2][1]=1;
D.m[2][2]=0;
}
Matrix multi(Matrix A,Matrix B)
{
Matrix ans;
for(int i=1;i<=2;i++)
for(int j=1;j<=2;j++)
{
ans.m[i][j]=0;
for(int k=1;k<=2;k++)
ans.m[i][j]+=A.m[i][k]*B.m[k][j];
}
return ans;
}
Matrix Pow(Matrix A,int k)
{
Matrix ans=E;
while(k)
{
if(k&1)
{
k--;
ans=multi(ans,A);
}
else
{
k/=2;
A=multi(A,A);
}
}
return ans;
}
int main()
{
int n;
while(scanf("%d%lf",&n,&p)!=EOF)
{
init();
Matrix tmp,cnt;
bool tag=0;
for(int i=1;i<=n;i++)
scanf("%d",&mines[i]);
mines[0]=0;
sort(mines,mines+n+1);
for(int i=1;i<=n;i++)
if(mines[i]==mines[i-1]+1)
{
tag=1;
break;
}
if(tag)
{
printf("%.7lf\n",0);
continue;
}
double ans=1;
tmp.m[1][1]=1; //dp[1]=1;
tmp.m[2][1]=0; //dp[0]=0;
for(int i=1;i<=n;i++)
{ // 对于每个雷,我们要到达的地点是 mines[i]-1
cnt=Pow(D,mines[i]-mines[i-1]-2);
tmp=multi(cnt,tmp);
// 然后走两步越过雷
tmp.m[1][1]*=(1-p);
// 走一步的结果
tmp.m[2][1]=0;
}
printf("%.7lf\n",tmp.m[1][1]);
}
return 0;
}