分析:
可以看出一个很naive的转移方程:
f[i]=p∗f[i−1]+(1−p)∗f[i−2]
f
[
i
]
=
p
∗
f
[
i
−
1
]
+
(
1
−
p
)
∗
f
[
i
−
2
]
(
i−1,i−2
i
−
1
,
i
−
2
都不是地雷)
在两个相邻的地雷之中,有一段安全区域
我突然发现,通过这个安全区域的方案数恰好是斐波那契数列(
f[i]=f[i−1]+f[i−2]
f
[
i
]
=
f
[
i
−
1
]
+
f
[
i
−
2
]
)
(方案数,立刻想到了这道题的处理方式,然而并没什么用)
计算斐波那契数列,一般都是使用矩阵乘法
那么这个转移方程我们也可以用矩阵加速
只要把安全区域和地雷分开考虑就好了
安全区域用矩阵,地雷直接乘上 (1−p) ( 1 − p )
tip
注意特殊情况
想好矩阵每个位置代表的意义
献上一种很神的数学做法
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
struct node{
double H[2][2];
node operator *(const node &a) const {
node ans;
for (int i=0;i<=1;i++)
for (int j=0;j<=1;j++) {
ans.H[i][j]=0.0;
for (int k=0;k<=1;k++)
ans.H[i][j]=ans.H[i][j]+H[i][k]*a.H[k][j];
}
return ans;
}
void clear() {
for (int i=0;i<=1;i++) for (int j=0;j<=1;j++) H[i][j]=0.0;
}
node KSM(int k) {
if (k==0) {
node ans;
ans.clear();
ans.H[0][0]=ans.H[1][1]=1.0;
return ans;
}
k--;
node ans=(*this),a=(*this);
while (k) {
if (k&1) ans=ans*a;
a=a*a;
k>>=1;
}
return ans;
}
};
node H;
int n,a[12];
double p;
int main()
{
while (scanf("%d%lf",&n,&p)!=EOF) {
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
H.clear();
H.H[0][0]=p; H.H[1][0]=1.0-p; H.H[0][1]=1.0;
sort(a+1,a+1+n); a[0]=0;
if (a[1]==1) {
printf("%0.7lf\n",0);
continue;
}
bool f=0;
double ans=1;
for (int i=1;i<=n;i++) {
if (a[i]==a[i-1]+1) {f=1;break;} //连续两个地雷
node A=H.KSM(a[i]-a[i-1]-2);
ans=ans*A.H[0][0]*(1.0-p);
}
if (!f) printf("%.7lf\n",ans);
else printf("%.7lf\n",0);
}
return 0;
}