1. 程式人生 > >Scout YYF I 概率dp + 矩陣快速冪

Scout YYF I 概率dp + 矩陣快速冪

/*
    題目描述:在一條道路上,每個位置有1個編號,編號分別是1 , 2 , ......現在有n(1 <= n <= 10)顆地雷,第i個分佈位置的
                處的編號為x[i],其中1 <= x[i] <= 100000000   現有一個人從位置1開始,問他在不踩到地雷的情況下穿過這條路
                的概率
                
    方法:設dp[i]表示剛走過第i個地雷而且活著的概率,而剛走過第i個地雷,就說明這個人現在的位置是x[i] + 1,因為經
        過地雷只有一種情況,就是從x[i] - 1到x[i] + 1。
                設step[i]表示從下標為p處走到p + i處的概率,可知step[i] = p * step[i - 1] + (1 - p) * step[i - 2],且step[0] = 1,
        step[1] = p,因為需要計算的i可能等於1e8,所以step的計算需要矩陣快速冪,矩陣的形式如下:
                |  p    1-p|^(n - 1)  | p  0|     =       | step[n]        0|
                |  1     0 |          | 1  0|             | step[n - 1]    0|
                那麼,dp[i] = dp[i - 1] *(step[dis] - p * step[dis - 1])       dis是從x[i - 1] + 1到x[i] + 1需要走的步數
        具體見程式碼
*/
#pragma warning(disable:4786)
#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<cmath>
#include<string>
#include<sstream>
#include<bitset>
#define LL long long
#define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define lson l,m,x<<1
#define rson m+1,r,x<<1|1
using namespace std;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps=1e-6;
const int maxn = 50 + 5;
const int NUM = 2;
double dp[maxn];
int x[maxn];
struct Matrix
{
    double a[NUM][NUM] ;
    void init(){
        mem(a , 0);
        for(int i = 0 ; i<NUM ; i++){
            a[i][i] = 1;
        }
    }
};
Matrix mul(Matrix a , Matrix b)
{
    Matrix ans;
    for(int i = 0 ; i< NUM ; i++){
        for(int j = 0 ; j<NUM ; j++){
            ans.a[i][j] = 0;
            for(int k = 0 ; k<NUM ; k++){
                ans.a[i][j] += a.a[i][k] * b.a[k][j];
            }
        }
    }
    return ans;
}
Matrix qpow(Matrix a , int n)
{
    Matrix ans;
    ans.init();
    while(n){
        if(n & 1)       ans = mul(ans , a);
        n >>= 1;
        a = mul(a , a);
    }
    return ans;
}
int main()
{
    int n;
    double p;
    while(scanf("%d %lf", &n , &p) != EOF){
        for(int i = 1 ; i <= n ; i++){
            scanf("%d", &x[i]);
        }
        Matrix multi , origin;
        multi.a[0][0] = p;      multi.a[0][1] = 1 - p;
        multi.a[1][0] = 1;      multi.a[1][1] = 0;
        mem(origin.a , 0);
        origin.a[0][0] = p;
        origin.a[1][0] = 1;
        sort(x + 1 , x + 1 + n);
        int flag = 1;
        for(int i = 2 ; i<= n ; i++){
            if(x[i] == x[i - 1]){
                flag = 0;
                break;
            }
        }
        if(x[1] == 1)   flag =0;
        if(!flag){
            puts("0.0000000");
            continue;
        }
        int pos = 1;
        dp[0] = 1;
        for(int i = 1 ; i<= n ; i++){
            int dis = x[i] + 1 - pos;
            Matrix ret = mul(qpow(multi , dis - 1) , origin);
            double pro1 = ret.a[0][0] , pro2 = ret.a[1][0];
            dp[i] = dp[i - 1] * (pro1 - p * pro2);
            pos = x[i] + 1;
        }
        printf("%.7lf\n",dp[n]);
    }
    return 0;
}