POJ 3744 Scout YYF I (概率DP初涉+矩阵快速幂加速)【模板】

来源:互联网 发布:coc闪电药水数据 编辑:程序博客网 时间:2024/06/05 05:14

YYF is a couragous scout. Now he is on a dangerous mission which is to penetrate into the enemy's base. After overcoming a series difficulties, YYF is now at the start of enemy's famous "mine road". This is a very long road, on which there are numbers of mines. At first, YYF is at step one. For each step after that, YYF will walk one step with a probability of p, or jump two step with a probality of 1- p. Here is the task, given the place of each mine, please calculate the probality that YYF can go through the "mine road" safely.
Input
The input contains many test cases ended with EOF
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
For each test case, output the probabilty in a single line with the precision to 7 digits after the decimal point.
Sample Input
1 0.522 0.52 4
Sample Output
0.50000000.2500000

 【题解】

 这是我接触概率DP的第一道题,比较简单,适合入门。

 题意就是在一个很长的路上,有m个地雷,位置分别是a[0],a[1],...a[m-1],现在yyf站在起点处,他有p的可能向前走一步,1-p的可能向前走两步,问yyf要安全的穿过这条路的概率。

 先正常思维, 假设路上有5个无地雷的点:①         ②            ③            ④           ⑤  

 那么到达各个点的概率是:                        1         0.5            0.75       0.6875      0.71825

  计算方法就是dp[i]=p*dp[i-1]+(1-p)*dp[i-2];

 但是地图中有地雷,不能踩,所以方法就要再思考一下,,能不能把它变成上述没有地雷的情况。

 很显然,我们只要把它分段就好了;

 第一段:0~a[0];

 第二段:a[0]+1~a[1];

 ...

 第n段: a[m-2]+1~a[m-1];

 这样我们就把这段路分成了末尾是地雷的m段,每段前面部分都满足上述情况,而我们要求不能踩地雷,所以就相当于每次要到达a[i]+1,而到达该点的概率恰好就是1-到达段末地雷处的概率,即p[a[i]+1] = 1 - p[a[i]];

 那么这个过程就清楚了,然后就要考虑,点的范围很大(1e8),1s勉强不会炸,但是想稳点,还得优化,所以得用矩阵快速幂加速,就比如1到300之间没有地雷,但是正常算的话得O(300)复杂度,而快速幂加速的话只需要O(log300),大大降低时间复杂度,这样就可以稳过了。

 

【AC代码】

 

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<math.h>using namespace std;int m;int a[11]; //最多只有10个地雷double p;struct Matrix{    double rate[2][2];};Matrix matrix(Matrix x,Matrix y) //矩阵乘法{    Matrix ss;    memset(ss.rate,0,sizeof ss.rate);    for(int i=0;i<2;++i)        for(int j=0;j<2;++j)            for(int k=0;k<2;++k)            ss.rate[i][j]+=x.rate[i][k]*y.rate[k][j];    return ss;}Matrix pow_m(Matrix n,int k) //矩阵快速幂{    Matrix tmp;    memset(tmp.rate,0,sizeof tmp.rate);    for(int i=0;i<2;++i)        tmp.rate[i][i]=1;    while(k)    {        if(k&1) tmp = matrix(tmp,n);        n=matrix(n,n);        k>>=1;    }    return tmp;}int main(){    while(~scanf("%d%lf",&m,&p))    {        for(int i=0;i<m;++i)            scanf("%d",&a[i]);        sort(a,a+m);        double ans=1;        Matrix ma;        ma.rate[0][0]=p;        ma.rate[0][1]=1-p;        ma.rate[1][0]=1.0;        ma.rate[1][1]=0.0;        Matrix mat;        mat= pow_m(ma,a[0]-1);        ans*=(1-mat.rate[0][0]);        for(int i=1;i<m;++i)        {            if(a[i]==a[i-1]) continue;            mat = pow_m(ma,a[i]-a[i-1]-1);            ans*=(1-mat.rate[0][0]);        }        printf("%.7f\n",ans);    }    return 0;}


原创粉丝点击