[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;
}
posted @ 2022-08-10 17:35  lxzy  阅读(26)  评论(0)    收藏  举报