概率期望 WOJ 1111 钉子和小球

描述

有一个三角形木板,竖直立放,上面钉着n(n+1)/2颗钉子,还有(n+1)个格子(当n=5时如图1)。每颗钉子和周围的钉子的距离都等于d,每个格子的宽度也都等于d,且除了最左端和最右端的格子外每个格子都正对着最下面一排钉子的间隙。 让一个直径略小于d的小球中心正对着最上面的钉子在板上自由滚落,小球每碰到一个钉子都可能落向左边或右边(概率各1/2),且球的中心还会正对着下一颗将要碰上的钉子。例如图2就是小球一条可能的路径。 我们知道小球落在第i个格子中的概率,其中i为格子的编号,从左至右依次为0,1,...,n。 现在的问题是计算拔掉某些钉子后,小球落在编号为m的格子中的概率pm。假定最下面一排钉子不会被拔掉。例如图3是某些钉子被拔掉后小球一条可能的路径。

Input

第1行为整数n(2<=n<=50)和m(0<=m<=n)。以下n行依次为木板上从上至下n行钉子的信息,每行中‘*’表示钉子还在,‘.’表示钉子被拔去,注意在这n行中空格符可能出现在任何位置。

Output

仅一行,是一个既约分数(0写成0/1),为小球落在编号为m的格子中的概pm。既约分数的定义:A/B是既约分数,当且仅当A、B为正整数且A和B没有大于1的公因子。

Sample Input

5 2


*

* .

* * *

* . * *

* * * * *

Sample Output

7/16

题解

概率dp
从当前行考虑下一行
若当前为“*”,则f[i+1][j]+=f[i][j]/2 f[i+1][j+1]+=f[i][j]/2
否则为f[i+2][j+1]+=f[i][j]
注意读入要注意空格,若用cin则可以忽略空格

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,m;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll f[55][55];
char c[55][55];
int main()
{
	cin>>n>>m;
	ll ans=1;
	for(int i=1;i<=n;i++)
		ans*=2;
	f[1][1]=ans;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=i;j++)
			cin>>c[i][j];
	for(int i=1;i<=n+1;i++)
	{	
		for(int j=1;j<=i;j++)
		{
			if(c[i][j]=='*')
			{
				f[i+1][j+1]+=f[i][j]/2;
				f[i+1][j]+=f[i][j]/2;
			}
			else if(c[i][j]=='.')
				f[i+2][j+1]+=f[i][j];
		}
	}
	if(f[n+1][m+1]==0) printf("0/1");
	else
	{
		ll t=gcd(ans,f[n+1][m+1]);
		printf("%lld/%lld",f[n+1][m+1]/t,ans/t);
	}
//	cout<<"\n";
//	for(int i=1;i<=n+1;i++)
//	{
//		for(int j=1;j<=i;j++)
//			cout<<f[i][j]<<" ";
//		cout<<"\n";
//	}
}
/*
5 2
*
*.
***
*.**
*****
*/
posted @ 2021-07-23 15:36  Socratize  阅读(71)  评论(0)    收藏  举报