POJ 3744 Scout YYF I 概率dp+矩阵快速幂
题目链接:
http://poj.org/problem?id=3744
Scout YYF I
Memory Limit: 65536K
输入
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].
输出
For each test case, output the probabilty in a single line with the precision to 7 digits after the decimal point.
样例输入
1 0.5
2
2 0.5
2 4
样例输出
0.5000000
0.2500000
题意
一个人从1号节点出发向右走,有n个位子有地雷,这个人走一步的概率为p,走两步的概率为1-p,现在问这个人安全走过去的概率为多少。
题解
由于雷很少,所以可以单独处理下有地雷的位置的时候的转移,比如x的位置有雷,那么就有
dp[x+1]=dp[x-1]*(1-p),dp[x+2]=dp[x+1]*p
,。其他一整片没有雷的就直接矩阵快速幂干过去(类似于斐波那契数列),起始位置的概率为1.0,然后模拟扫过去求出dp[last+1]就可以了(last指最后一个雷的位置)。
代码
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define scf scanf
#define prf printf
typedef __int64 LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII;
const int INF=0x3f3f3f3f;
const LL INFL=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-9;
const double PI = acos(-1.0);
//start----------------------------------------------------------------------
const int maxn=2;
struct Matrix{
double mat[maxn][maxn];
Matrix(){ clr(mat,0); }
friend Matrix operator *(const Matrix& A,const Matrix& B){
Matrix ret;
for(int i=0;i<maxn;i++){
for(int j=0;j<maxn;j++){
for(int k=0;k<maxn;k++){
ret.mat[i][j]=ret.mat[i][j]+A.mat[i][k]*B.mat[k][j];
}
}
}
return ret;
}
}I;
Matrix pow(Matrix A,int n){
Matrix ret=I;
while(n){
if(n&1) ret=ret*A;
A=A*A;
n/=2;
}
return ret;
}
int n;
double p;
int main() {
rep(i,0,maxn) I.mat[i][i]=1;
while(scf("%d%lf",&n,&p)==2&&n){
vector<int> arr;
rep(i,0,n){
int x; scf("%d",&x);
arr.pb(x);
}
sort(all(arr));
arr.erase(unique(all(arr)),arr.end());
if(arr.sz()==0){ prf("1.0000000\n"); continue; }
bool su=true;
if(arr[0]==1) su=false;
else{
for(int i=0;i<arr.sz()-1;i++){
if(arr[i+1]-arr[i]==1){
su=false; break;
}
}
}
if(!su){ prf("0.0000000\n"); continue; }
Matrix A;
A.mat[0][0]=p, A.mat[0][1]=1-p;
A.mat[1][0]=1, A.mat[1][1]=0;
double pre=1.0;
for(int i=0;i<arr.sz();i++){
int cnt;
if(i==0) cnt=arr[i]-1;
else cnt=arr[i]-arr[i-1]-1;
if(cnt==1){ pre*=(1-p); }
else{
double f0=pre,f1=pre*p;
Matrix vec;
vec.mat[0][0]=pre*p;
vec.mat[1][0]=pre;
vec=pow(A,cnt-2)*vec;
pre=vec.mat[0][0];
pre*=(1-p);
}
}
prf("%.7f\n",pre);
}
return 0;
}
//end-----------------------------------------------------------------------