题目大意:一个数轴上有n个地雷,坐标给定,熊孩子一开始在位置1,每次向前跳1格的概率是p,跳两格的概率是1-p,求他安全跳过这n个地雷的概率。
第一次写概率DP,WA了两发以后莫名其妙就AC了。。。太弱了。。。
首先对于一个地雷,我们肯定是要一次跳两格来过去;而每两个地雷之间的区间是安全的,我们可以直接用f[i]=f[i-1]*p+f[i-2]*(1-p)推算,f[i]表示到位置i的概率。假设我们求出经过第一段安全区间的概率是P1,第二段是P2。。。那么最后结果就是P1*(1-p)*P2*(1-p)*.....*Pn*(1-p)。因为区间比较长所以要用矩阵快速幂优化。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define rep(i,n) for (int i=1;i<=n;i++)
const int N=20;
struct mat{
int n,m;
double a[4][4];
void init(int x,int y){
memset(a,0,sizeof a);
n=x;m=y;
}
}ini,org;
int n,a[N];
double p,ans;
mat operator *(const mat A,const mat B){
mat C;
C.init(A.n,B.m);
rep(i,C.n) rep(j,C.m) rep(t,A.m)
C.a[i][j]+=A.a[i][t]*B.a[t][j];
return C;
}
double calc(int t){
mat unit=org,ret;
ret.init(2,2);
ret.a[1][1]=ret.a[2][2]=1;
for (;t;t>>=1,unit=unit*unit)
if (t&1) ret=ret*unit;
return ret.a[1][1];
}
int main(){
ini.init(1,2);
ini.a[1][1]=1;ini.a[1][2]=0;
while (~scanf("%d %lf",&n,&p)){
rep(i,n) scanf("%d",&a[i]);
sort(a+1,a+n+1); //记得要排序
org.init(2,2);
org.a[1][1]=p;org.a[1][2]=1;
org.a[2][1]=1-p;
bool can=1;
ans=1;
rep(i,n){
if (a[i]==a[i-1]) continue;
if (a[i]-1==a[i-1]) {
can=0;
break;
}
ans=ans*calc(a[i]-a[i-1]-2)*(1-p);
}
if (!can) printf("0.0000000\n");
else printf("%.7lf\n",ans);
}
return 0;
}