[POJ3744]Cout YYF I
做题时间:2022.8.10
\(【题目描述】\)
在数轴上有 \(N(1\leq N\leq 10)\) 个关键点,位置为 \(d_i(1\leq d_i\leq 10^8)\) ,现在从位置 \(1\) 开始,每次有 \(p\) 的概率向右走 \(1\) 个单位长度,有 \((1-p)\) 的概率向右走 \(2\) 个单位长度,问不走到关键点并通过数轴的概率。
\(【输入格式】\)
多组数据
对于每组数据第一行两个数 \(N\) 和 \(p\)
第二行 \(N\) 个整数 \(d_i\) 表示关键点位置
\(【输出格式】\)
对于每组数据,输出一行一个实数表示答案(保留7位小数)
\(【考点】\)
概率DP、矩阵快速幂
\(【做法】\)
首先可以想到定义 \(f_i\) 表示走到位置 \(i\) 的概率,然后有:
\[f_i=\left\{ \begin{aligned} 0 & & d_p=i \\ f_{i-1}\cdot p+f_{i-2}\cdot (1-p) & & \text{otherwise.} \end{aligned} \right.
\]
直接dp会超时,由于 \(f_i\) 只和前两项有关,且 \(N\) 只有10,可以考虑以每一个关键点为分界分段快速幂,即将关键点排序,用矩阵快速幂求出 \(f_{d_1-1},f_{d_1}\) 的值,在有 \(f_{d_1}=0\) ,然后以他们为启示继续跑矩阵快速幂……
\(【做法】\)
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
using namespace std;
int n,x[12],ed;
double f[4],p;
struct Matrix{
double num[3][3];
Matrix(){memset(num,0,sizeof num);}
Matrix operator *(const Matrix &b){
Matrix c;
for(int i=1;i<=2;i++){
for(int j=1;j<=2;j++){
for(int k=1;k<=2;k++){
c.num[i][j]+=num[i][k]*b.num[k][j];
}
}
}
return c;
}
}a,m,One;
Matrix Pow(Matrix a,int b)
{
Matrix ans=One,base=a;
while(b){
if(b&1) ans=ans*base;
base=base*base;
b>>=1;
}
return ans;
}
int main()
{
One.num[1][1]=One.num[2][2]=1;
while(scanf("%d",&n)!=EOF){
scanf("%lf",&p);
m.num[1][2]=1-p,m.num[2][1]=1;
m.num[2][2]=p;
ed=0;
for(int i=1;i<=n;i++){
scanf("%d",&x[i]);
ed=max(ed,x[i]);
}
sort(x+1,x+1+n);
Matrix F;
F.num[1][2]=(x[1]==1?0:1);
x[0]=1;
for(int i=1;i<=n;i++){
F=F*Pow(m,x[i]-x[i-1]);
F.num[1][2]=0;
}
double ans=F.num[1][2]*p+F.num[1][1]*(1-p);
printf("%.7lf\n",ans);
}
return 0;
}

浙公网安备 33010602011771号