Scout YYF I 概率dp + 矩陣快速冪
阿新 • • 發佈:2019-01-27
/* 題目描述:在一條道路上,每個位置有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; }