POJ 3744 Scout YYF I 矩阵快速幂+概率dp

题意:

  yyf每次能走一步或二步概率为p和1-p

路上有n个地雷  分布在di位置上

问yyf能安全通过这条路的概率

分析

可以容易的得出 dp【i】=p*dp[i-1]+(1-p)*dp[i-2]

因为路长是1e9推会爆炸考虑利用矩阵快速幂优化

要安全跨过某个地累则一定是在地雷的前一步的地方一次性走两布

然后把通过所有地雷的概率连乘就是答案

ACcode:

#pragma warning(disable:4786)//使命名长度不受限制
#pragma comment(linker, "/STACK:102400000,102400000")//手工开栈
#include <map>
#include <set>
#include <queue>
#include <cmath>
#include <stack>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define rd3(x,y,z) scanf("%d%d%d,&x,&y,&z)
#define rdl(x) scanf("%I64d,&x);
#define rds(x) scanf("%s",x)
#define rdc(x) scanf("%c",&x)
#define ll long long int
#define ull unsigned long long
#define maxn 1005
#define mod 1000000007
#define INF 0x3f3f3f3f //int 最大值
#define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;++i)
#define MT(x,i) memset(x,i,sizeof(x))
#define PI  acos(-1.0)
#define E  exp(1)
#define eps 1e-8
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll mul(ll a,ll b,ll p){ll sum=0;for(;b;a=(a+a)%p,b>>=1)if(b&1)sum=(sum+a)%p;return sum;}
inline void Scan(int &x) {
      char c;while((c=getchar())<'0' || c>'9');x=c-'0';
      while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
}
using namespace std;
struct N{
    double mat[2][2];
};
N mul(N a,N b){
    N ret;
    for(int i=0;i<2;++i)
        for(int j=0;j<2;++j){
            ret.mat[i][j]=0;
            for(int k=0;k<2;++k)
                ret.mat[i][j]+=a.mat[i][k]*b.mat[k][j];
        }
    return ret;
}
N pow_M(N a,int n){
    N ret;
    memset(ret.mat,0,sizeof(ret.mat));
    for(int i=0;i<2;++i)ret.mat[i][i]=1;
    N tmp=a;
    while(n){
        if(n&1)ret=mul(ret,tmp);
        tmp=mul(tmp,tmp);
        n>>=1;
    }
    return ret;
}
int a[12];
int main(){
    int n,loop,cnt=1;
    double p1,p2;
    while(~scanf("%d%lf",&n,&p1)){
        p2=1.0-p1;
        for(int i=1;i<=n;++i)scanf("%d",&a[i]);
        sort(a+1,a+1+n);
        N tmp,kkk ;
        tmp.mat[0][0]=p1,tmp.mat[0][1]=p2;
        tmp.mat[1][0]=1,tmp.mat[1][1]=0;

        kkk=pow_M(tmp,a[1]-1);
        double ans=1-kkk.mat[0][0];
        for(int i=2;i<=n;++i){
            if(a[i]==a[i-1]){
                    ans=0;
                    break;
            }
            kkk=pow_M(tmp,a[i]-a[i-1]-1);
            ans*=(1-kkk.mat[0][0]);
        }
        printf("%.7f\n",ans);
    }
    return 0;
}
/*
3 0.7
2 4 9
4 0.1
2 3 5 11
4 0.34
1 8 22 4
4 0.7
4 8 14 22
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值