UOJ Logo Ignatz的博客

博客

poj 3744

2015-12-21 13:03:36 By Ignatz

$poj\ 3744$

题目大意

区间$[1,10^9]$内有$n(n \leq 10)$个地雷$a_1 \dots a_n$,从$1$出发,每次走$1$或$2$步,走$1$步的概率是$p$,走$2$步的概率是$1-p$,求安全走出雷区的概率。

方程

$$ f_i= \left\{ \begin{array}{ll} 0 & \textrm{$i \in {a}$} \\ p \cdot f_{i-1} + (1-p) \cdot f_{i-2} & \textrm{else} \end{array} \right. $$

$n_0=2$,特判$1$处是否有地雷, $\mathbf{F(2)}= \left( \begin{array}{c} p & 1 \end{array} \right)$

$sort(a)$,构造矩阵$\mathrm{R}$,分段求解,$f_{a_n+1}$即为所求。

$$ \mathbf{R}= \left( \begin{array}{cc} p & 1 \\ 1-p & 0 \end{array} \right) $$

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define rep(i,x,y) for (int i=x; i<=y; ++i)

using namespace std;
struct mat
{
    int n,m;
    double v[2][2];
    mat(){}
    mat(int a,int b):n(a),m(b)
    {
        memset(v,0,sizeof(v));
    }
    double *operator [] (int x)
    {
        return v[x];
    }
} r,s,t;
int n,a[11];
double p;

inline void operator *= (mat &a,mat b)
{
    double t[2];
    rep(i,0,a.n)
    {
        memset(t,0,sizeof(t));
        rep(j,0,a.m)
            rep(k,0,a.m)
                t[j]+=a[i][k]*b[k][j];
        memcpy(a[i],t,sizeof(t));
    }
}

int main()
{
    while (scanf("%d%lf",&n,&p)==2)
    {
        a[0]=2;
        rep(i,1,n)
            scanf("%d",a+i);
        sort(a+1,a+1+n);
        if (a[1]==1)
        {
            puts("0.0000000");
            continue;
        }
        r=mat(1,1),s=mat(0,1);
        r[0][0]=p,r[1][0]=1-p,r[0][1]=1;
        s[0][0]=p,s[0][1]=1;
        rep(i,1,n)
        {
            if (!s[0][0] && !s[0][1])
                break;
            t=r;
            for (int j=a[i]-a[i-1]; j; j>>=1,t*=t)
                if (j&1)
                    s*=t;
            s[0][0]=0;
        }
        printf("%.7f\n",s[0][0]*p+s[0][1]*(1-p));
    }
    return 0;
}

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。