/*
题意:在一条不满地雷的路上,你现在的起点在1处。
在N个点处布有地雷,1<=N<=10。地雷点的坐标范围:[1,100000000].
每次前进p的概率前进一步,1-p的概率前进两步。
问顺利通过这条路的概率。就是不要走到有地雷的地方。
dp[i] 表示走到i的概率
dp[i+1]=dp[i]*p+dp[i-1]*(1-p);
用矩阵快速幂优化
递推式转矩阵
| 0 1| |dp(k-1)| = | dp(k) |
| 1-p p| | dp(k) | | dp(k+1)|
dp[0]=0,dp[1]=1;
设x[i] 表示第i个地雷的位置
把道路分成开
1~x[1] x[1]+1~x[2]...... x[n-1]+1~x[n]
对于每一段 sus[i] 表示 x[i-1]+1~x[i]-1这一段没有挂掉
那么sus[i]= 1-从x[i-1]+1刚好走到x[i]的概率;
那么 ans为sus[i]的总乘积(即每一段都没屎)
*/
#include <stdio.h>
#include <algorithm>
#include <vector>
using namespace std;
typedef vector<double> vec;
typedef vector<vec> mat;
const int maxn=30;
const double eps=1E-8;
int x[maxn];
int n;
double p;
mat mul(const mat &a,const mat &b)
{
mat c(2,vec(2,0));
for(int i=0;i<2;++i)
for(int j=0;j<2;++j)
for(int k=0;k<2;++k)
c[i][j]+=a[i][k]*b[k][j];
return c;
}
double T(int k)
{
double s[2][2]={{0,1},{1-p,p}};
mat A(2,vec(2));
mat p(2,vec(2,0));
p[0][0]=p[1][1]=1;
for(int i=0;i<2;++i)
for(int j=0;j<2;++j)
A[i][j]=s[i][j];
while(k>0)
{
if(k&1)
p=mul(A,p);
k=k>>1;
A=mul(A,A);
}
return p[1][1];
}
void DP()
{
double ans=1;
double tmp=T(x[1]-1);
ans*=(1-tmp);
for(int i=2;i<=n;++i)
{
if(x[i]==x[i-1]) continue;
tmp=1-T(x[i]-x[i-1]-1);
ans*=tmp;
}
printf("%.7f\n",ans<eps?0:ans);
}
int main()
{
while(~scanf("%d %lf",&n,&p))
{
for(int i=1;i<=n;++i)
scanf("%d",x+i);
sort(x+1,x+1+n);
DP();
}
return 0;
}
poj-3744 Scout YYF I [用矩阵优化概率递推式]
最新推荐文章于 2020-05-08 22:38:43 发布