题目链接:点击打开链接
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 6890 | Accepted: 2004 |
Description
Input
Each test case contains two lines.
The First line of each test case is N (1 ≤ N ≤ 10) and p (0.25 ≤ p ≤ 0.75) seperated by a single blank, standing for the number of mines and the probability to walk one step.
The Second line of each test case is N integer standing for the place of N mines. Each integer is in the range of [1, 100000000].
Output
Sample Input
1 0.5 2 2 0.5 2 4
Sample Output
0.5000000 0.2500000
Source
题意:一条路有n个陷阱,起始点在1,每次走一步的概率是p,两步的概率是1-p,给出n个陷阱的位置,在[1, 100000000]之间,求安全通过的概率。思路:设点dp[n]为到达n的概率,则dp[n]=p*dp[n-1]+(1-p)*dp[n-2]
但是由于座标范围很大,直接这样求是不行的,而且当中的某些点还存在地雷。输入地雷座标x[i]
分段求通过1~x[0],x[0]+1~x[1].....,x[n-2]+1~x[n-1]的概率,乘法原理相乘就是最终的答案。
求dp[i]的时候,需要用到矩阵快速幂。那么通过每一段的概率就是1-dp[x[i]],同时需要保证每一段路的起点的概率是1,如dp[1]=1;
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct Mat
{
double mat[2][2];
};
Mat operator *(Mat a,Mat b)
{
Mat c;
memset(c.mat,0,sizeof(c.mat));
int i,j,k;
for(i=0;i<2;i++)
for(j=0;j<2;j++)
for(k=0;k<2;k++)
c.mat[i][j]+=a.mat[i][k]*b.mat[k][j];
return c;
}
Mat operator ^(Mat a,int k)
{
Mat c;
memset(c.mat,0,sizeof(c.mat));
int i,j;
for(i=0;i<2;i++)
for(j=0;j<2;j++)
if(i==j) c.mat[i][j]=1;
while(k)
{
if(k&1) c=operator *(c,a);
a=operator *(a,a);
k>>=1;
}
return c;
}
int main()
{
int n,i,x[15];double p,ans;
Mat a,b;
while(scanf("%d%lf",&n,&p)!=EOF)
{
memset(a.mat,0,sizeof(a.mat));
a.mat[0][0]=p;a.mat[0][1]=1-p;
a.mat[1][0]=1;a.mat[1][1]=0;
for(i=0;i<n;i++)
scanf("%d",&x[i]);
sort(x,x+n);
ans=1;
b=operator ^(a,x[0]-1);
ans*=(1-b.mat[0][0]);
for(i=1;i<n;i++)
{
if(x[i]==x[i-1]) continue;
b=operator ^(a,x[i]-x[i-1]-1);
ans*=(1-b.mat[0][0]);
}
printf("%.7lf\n",ans);
}
}