【POJ】3744 Scout YYF I
http://poj.org/problem?id=3744
题意:直线上n个地雷,n<=10,范围在[1, 100000000],每一次有p的概率向前走一步,1-p的概率向前走两步,问安全通过所有地雷的概率(即走到最后一个地雷的后一格)
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef double mtx[2][2]; void mul(mtx &a, mtx &b, mtx &c) { static mtx t; for(int i=0; i<2; ++i) for(int j=0; j<2; ++j) { t[i][j]=0; for(int k=0; k<2; ++k) t[i][j]=t[i][j]+a[i][k]*b[k][j]; } memcpy(c, t, sizeof t); } double P; bool flag; void mpow(mtx &t, int n) { if(n<0) { memset(t, 0, sizeof t); flag=1; return; } if(flag) return; static mtx a, x; a[0][0]=P; a[0][1]=1; a[1][0]=1-P; a[1][1]=0; memset(x, 0, sizeof x); x[0][0]=1; x[1][1]=1; while(n) { if(n&1) mul(x, a, x); mul(a, a, a); n>>=1; } mul(t, x, t); } mtx a, b; int x[15], n; int main() { memset(b, 0, sizeof b); while(~scanf("%d%lf", &n, &P)) { for(int i=1; i<=n; ++i) scanf("%d", &x[i]); sort(x+1, x+1+n); b[0][0]=1-P; flag=0; memset(a, 0, sizeof a); a[0][0]=1; for(int i=1; i<=n; ++i) mpow(a, x[i]-x[i-1]-2), mul(a, b, a); a[0][0]=(a[0][0]<0?-a[0][0]:a[0][0]); printf("%.7f\n", a[0][0]); } return 0; }
对于每一步状态$d[i]$,发现是由$d[i-1]$和$d[i-2]$转移得到的,那么由于事件$i-1$和事件$i-2$互斥,且根据概率的线性性质,得到:
$d[i]=p*d[i-1]+(1-p)*d[i-2]$
可是有地雷怎么办?分段= =然后讨论之= =
发现范围很大怎么办?转移一样上矩阵= =
反正最后得到矩阵积是这个样子的:
$$
\begin{bmatrix}
1 & 0 \\
\end{bmatrix}
\prod_{i=1}^{n}
\left(
\begin{bmatrix}
p & 1 \\
1-p & 0
\end{bmatrix}^{x_i-x_{i-1}-2}
\begin{bmatrix}
1-p & 0 \\
0 & 0
\end{bmatrix} \right)
$$
然后就行了= =
注意$x$数组不是有序的= =需要排一次序.....要不然就wa了一发QAQ还有poj的bits/stdc++不能用是什么鬼 = =
博客地址:www.cnblogs.com/iwtwiioi 本文为博主原创文章,未经博主允许不得转载。一经发现,必将追究法律责任。