poj 3744 题解
题意: $ yyf $ 一开始在 $ 1 $ 号节点他要通过一条有 $ n $ 个地雷的道路,每次前进他有 $ p $ 的概率前进一步,有 $ 1-p $ 的概率前进两步,问他不领盒饭的概率。
对于这道题我们可以考虑 $ dp $ ,我们可以设计状态 $ f[i] $ 表示安全通过 $ i $的概率,那么我们可以得到状态转移方程
$ f[i]=p* f[i-1]+(1-p)* f[i-2] $
$ f[x_i]=0 $
然后我们可以看到 $ x \in [1, 100000000] $如果我们直接 $ dp $ 很明显会超时那么怎么办呢?我们可以去考虑进行分段 $ dp $ 。我们可以观察发现在你到一个地雷前,这其中的概率只与这个地雷有关就可以把区间进行缩小然后 $ dp $
$ a[1],a[2],a[3]......a[x[1]] $
$ a[x[1]+1],a[x[1]+2],a[x[1]+3]......a[x[2]] $
$ .......... $
$ a[x[n-1]+1],a[x[n-1]+2],a[x[n-1]+3]......a[x[n]] $
然后我们看到这个状态转移方程
$ f[i]=p* f[i-1]+(1-p)* f[i-2] $
是不是很像
$ f[i]=f[i-1]+ f[i-2] $
就可以看作斐波那契数列加了个参数可以使用矩阵加速(对于这个网上有很多题解,这里就不讲这个讲下别的)
首先我们可以写出它的特征方程 $ x^2=px+* (1-p) $
移项后得 $ x^2-px+p-1=0 $
利用求根公式得到两个不同的可行解 $ x_1=p-1 \ \ \ \ x_2= 1 $
就可以写出通项公式 $ f(n)=c_1x_1n+c_2x_2n $
即 $ f(n)=c_1* 1^n +c_2 * (p-1)^n $
然后我们可以将 $ f(1)=1,f(2)=p $ 带入可以知道 $ c_1=\frac{1}{2-p} \ \ \ c_2=\frac{1}{p-2} $
最后的通项公式就是 $ f(n)=\frac{1-(p-1)^n}{2-p} $
最后用快速幂求出 $ 1-(p-1)^n $ 即可
代码
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int n,x[30];
double p,ans;
double power(int y){
double tmp=1;double x=p-1.0;//注意类型
while(y){
if(y&1) tmp*=x;
x*=x;
y>>=1;
}
return tmp;
}
int main(){
while(scanf("%d %lf",&n,&p)!=EOF){
for(int i=1;i<=n;++i) scanf("%d",&x[i]);
ans=1;x[0]=0;
sort(x+1,x+1+n);//原来的地雷不一定有序
for(int i=1;i<=n;++i){
int tmp=x[i]-x[i-1]-1;//走到地雷前
ans*=((1.0-power(tmp))/(2.0-p));
if(fabs(ans)<1e-8) break;//为0直接退出
ans*=(1.0-p);//跳过地雷,走两步
}
printf("%.7lf\n",ans);
}
return 0;
}