題目鏈接:點擊打開鏈接
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);
}
}