题干:
题目大意:
在一条不满地雷的路上(无限长),你现在的起点在1处。在N个点处布有地雷,1<=N<=10。地雷点的可能坐标范围:[1,100000000].
每次前进p的概率前进一步,1-p的概率前进2步。问顺利通过这条路的概率。就是不要走到有地雷的地方。
设dp[i]表示到达i点且不踩地雷的概率,如果1号点没有地雷,则初始值 dp[1]=1.
很容易想到转移方程: dp[i]=p*dp[i-1]+(1-p)*dp[i-2];
解题报告:
不难发现,对于没有地雷的一段,可以用map来离散,然后用矩阵快速幂优化转移。每遇到一个地雷就断开一次,于是最多进行十次矩阵快速幂就可以解决。
AC代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define FF first
#define SS second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
struct Matrix {double m[2][2];
} unit,empty;
map<int,double> dp;
Matrix mul(Matrix a,Matrix b) {Matrix c = empty;for(int i = 0; i<2; i++) {for(int j = 0; j<2; j++) {for(int k = 0; k<2; k++) {c.m[i][j] += a.m[i][k]*b.m[k][j];}}} return c;
}
Matrix qpow(Matrix a,int b) {Matrix c = unit;while(b) {if(b&1) c = mul(c,a);b>>=1;a = mul(a,a);} return c;
}
int n,d[22];
double p;
int main()
{unit.m[1][1] = unit.m[0][0] = 1;while(~scanf("%d%lf",&n,&p)) {dp.clear();for(int i = 1; i<=n; i++) scanf("%d",d+i);sort(d+1,d+n+1);int flag = (d[1] != 1);for(int i = 1; i<n; i++) {if(d[i+1] - d[i] == 1) flag = 0;}if(flag == 0) {puts("0.0000000");continue;}Matrix trans,ans;trans.m[0][0]=p;trans.m[0][1] = 1-p;trans.m[1][0] = 1;trans.m[1][1]=0;dp[0] = 0;dp[1] = 1;int last = 1,tar;for(int i = 1; i<=n; i++) {tar = d[i] - 1;ans = qpow(trans,tar-last);dp[tar] = ans.m[0][0]*dp[last] + ans.m[0][1]*dp[last-1];last = tar+2; dp[last] = dp[tar]*(1-p);dp[d[i]]=0;}printf("%.7f\n",dp[tar]*(1-p));}return 0 ;
}