Time Limit: 1000MS | Memory Limit: 65536K | |
Description
Input
Output
Sample Input
1 0.5 2 2 0.5 2 4
Sample Output
0.5000000 0.2500000
题目大意:在一条很长的路上,有n个雷,给出每个雷的坐标,以及一个人每次走一步的概率p,走两步的概率为1-p,初始在点1处,求安全走过这段路的概率?
大致思路:设dp[i]表示安全到达点i处的概率,则状态转移方程为:
①点i处有雷,dp[i]=0;
②点i出无雷,dp[i]=dp[i-1]*p+dp[i-2]*(1-p);
由于雷坐标的范围很大,而雷的数量很少,所以需要用矩阵快速幂对无雷的路段进行优化
#include <cstdio> #include <algorithm> using namespace std; const int MAXN=2; int n,index[13]; double p,ans; struct Matrix{ double m[MAXN][MAXN]; }ORI; Matrix I = {1,0, 0,1}; Matrix matrixmul(const Matrix& a,const Matrix& b) {//矩阵乘法 int i,j,k; Matrix c; for (i = 0 ; i < MAXN; i++) for (j = 0; j < MAXN;j++) { c.m[i][j] = 0; for (k = 0; k < MAXN; k++) c.m[i][j] += a.m[i][k] * b.m[k][j]; } return c; } Matrix quickpow(int n) { Matrix m = ORI, b = I; while (n >= 1) { if (n & 1) b = matrixmul(b,m); n = n >> 1; m = matrixmul(m,m); } return b; } int main() { while(2==scanf("%d%lf",&n,&p)) { ORI.m[0][0]=p; ORI.m[0][1]=1; ORI.m[1][0]=1-p; ORI.m[1][1]=0; for(int i=1;i<=n;++i) { scanf("%d",index+i); } index[0]=0; sort(index,index+n+1); ans=1;//ans表示到达index[i]+1处的概率 for(int i=1;i<=n;++i) { if(index[i]!=index[i-1]) {//如果两个雷不在同一点 if(index[i]-index[i-1]==1) {//如果两个雷相邻,则无法安全通过 ans=0.00000001; break; } ans*=quickpow(index[i]-index[i-1]-2).m[0][0];//算出安全到达index[i]-1的概率 ans*=1-p;//算出安全到达index[i]+1的概率 } } printf("%.7lf\n",ans); } return 0; }
for(int i=1;i<=n;++i) { if(index[i]!=index[i-1]) {//如果两个雷不在同一点 ans*=(1-quickpow(index[i]-index[i-1]-1).m[0][0]);//直接算出安全到达index[i]+1的概率 } }