着实被批评了一下,自己的数论确实太烂了。
题意:一条路上,有n个炸弹,给出每个炸弹的位置,一次走一步的概率是p,走两步的概率是1-p。求安全走完的概率。
定义dp[i] = dp[i-1]*p + dp[i-2]*(1-p)
由于路很长,不能递推。
n个炸弹就把路分成了n+1段路,计算走完一段路安全的概率就行,然后相乘。
| p , 1 |
| dp[i-1],dp[i-2] | * | 1-p,0 | = | dp[i],dp[i-1] |
求安全走完一段长为L路的概率,就将矩阵乘L次即可,由于L可能很大,用二分法计算。
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; struct mat{ double a[2][2]; mat() {for(int i=0;i<2;i++) for(int j=0;j<2;j++) a[i][j]=0; } }; mat e; int n; double p; int num[20]; mat mul(mat a,mat b) { mat ans; for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++) ans.a[i][j]+=a.a[i][k]*b.a[k][j]; return ans; } double matPow(mat a,int k) { mat ans=e; while(k) { if(k&1) ans=mul(ans,a); a=mul(a,a); k=k>>1; } return ans.a[0][0]; } int main() { e.a[0][0]=1;e.a[1][0]=0; e.a[0][1]=0;e.a[1][1]=1; while(scanf("%d%lf",&n,&p)!=EOF) { num[0]=0; for(int i=1;i<=n;i++) scanf("%d",&num[i]); sort(num,num+n+1); double ans=1; mat res; res.a[0][0]=p;res.a[1][0]=1; res.a[0][1]=1-p;res.a[1][1]=0; for(int i=1;i<=n;i++) ans*=(1.0-matPow(res,num[i]-num[i-1]-1)); printf("%.7lf ",ans); } return 0; }