标签:
题意:一条路上有n个地雷,告诉你这n个雷的位置,一个人初始在位置1,这个人每次可以走1个单位或者跳2个单位,概率分别为p和1-p,现在要求这个人安全通过这段路的概率
思路:求出安全通过每个雷的概率,再把所有的乘起来即可。要安全通过某个雷(假设在place[i]这个位置),只有从place[i]-1跳两格才能安全通过。这样只要求出place[i-1]+1到place[i]-1的概率再乘上(1-p)就能得到通过第i个雷的概率。
由于数据较大,所以必须用矩阵快速幂。其实这是斐波拉契数列的一个变形:f(i)=f(i-1)*p+f(i-2)*(1-p) ;要快速求出f(i),使用矩阵快速幂即可。
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; int place[1010] ; double ep[1010] , p ,f1 ,f2; struct Mat{ double mat[10][10] ; }; Mat mul(Mat a,Mat b) { Mat ret; for(int i=0;i<2;i++) for(int j=0;j<2;j++) { ret.mat[i][j]=0; for(int k=0;k<2;k++) ret.mat[i][j]+=a.mat[i][k]*b.mat[k][j]; } return ret; } Mat pow_M(Mat a,int n) { Mat ret; memset(ret.mat,0,sizeof(ret.mat)); for(int i=0;i<2;i++)ret.mat[i][i]=1; Mat temp=a; while(n) { if(n&1)ret=mul(ret,temp); temp=mul(temp,temp); n>>=1; } return ret; } double Q_mul(int k) { Mat a; a.mat[0][0]=p, a.mat[0][1]=1.0-p ,a.mat[1][0]=1.0 ,a.mat[1][1]=0; Mat ret=pow_M(a,k); return (f2*ret.mat[1][0]+f1*ret.mat[1][1])*(1.0-p); } int main() { int n; while(cin>>n>>p){ memset(place,0,sizeof(place)) ; for(int i=0;i<n;i++){ scanf("%d",&place[i]) ; } sort(place,place+n) ; int now=1; double ans=1.0; if(place[0]==1){ printf("0.0000000\n") ; continue ; } for(int i=0 ; i<n ; i++){ //cout<<i<<" "<<place[i]<<" "<<now<<" "<<endl; if(place[i] == now){ now= -1; break; } else{ f1=1.0; if(now +1 == place[i]){ //cout<<1<<endl; ep[i] = f1*(1.0-p) ; } else{ f2=f1*(1.0*p) ; ep[i]=Q_mul(place[i]-(now+1)) ; //cout<<place[i]-(now+1)<<endl; } now=place[i] + 1 ; } } if(now==-1){ printf("0.0000000\n") ; } else{ for(int i=0 ;i <n ; i++){ //cout<<ep[i]<<endl; ans*=ep[i] ; } printf("%.7f\n",ans) ; } } return 0; }
标签:
原文地址:http://www.cnblogs.com/Scale-the-heights/p/4702990.html