原题:
有一个三角形木板,竖直立放,上面钉着n(n+1)/2颗钉子,还有(n+1)个格子(当n=5时如图1)。每颗钉子和周围的钉子的距离都等于d,每个格子的宽度也都等于d,且除了最左端和最右端的格子外每个格子都正对着最下面一排钉子的间隙。
让一个直径略小于d的小球中心正对着最上面的钉子在板上自由滚落,小球每碰到一个钉子都可能落向左边或右边(概率各1/2),且球的中心还会正对着下一颗将要碰上的钉子。例如图2就是小球一条可能的路径。
我们知道小球落在第i个格子中的概率pi=pi= ,其中i为格子的编号,从左至右依次为0,1,...,n。
现在的问题是计算拔掉某些钉子后,小球落在编号为m的格子中的概率pm。假定最下面一排钉子不会被拔掉。例如图3是某些钉子被拔掉后小球一条可能的路径。
题意:
题解:
因为要求珠子落在某个地方的概率,而要求的又是分数,所以最开始假设有2**n个珠子,这样如果不拔掉的话最变旁边的格子能落下一颗珠子,可以保证为整数。然后模拟这2**n颗珠子的下落轨迹,如果这个地方有钉子那么落到这的珠子左右平分dp[i+1][j]+=dp[i][j]/2; dp[i+1][j+1]+=dp[i][j]/2;如果这颗钉子被拔掉了那么直接下落两层dp[i+2][j+1]+=dp[i][j];
通过状态转移方程可以算出最后落到每个槽里有多少颗珠子,然后通过辗转相除法求出最大公约数,然后就可以求出分数的最简表示形式。
代码:AC
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long LL;
char a[55][55];
LL dp[55][55];
int n,m;
LL zhanzhuan(LL x,LL y)
{
if(y==0)
return x;
return zhanzhuan(y,x%y);
}
int main()
{
while(cin>>n>>m)
{
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<=i;j++)
{
cin>>a[i][j];
}
}
memset(dp,0,sizeof(dp));
LL max=pow(2.0,n);
dp[0][0]=max;
for(i=0;i<n;i++)
{
for(j=0;j<=i;j++)
{
if(a[i][j]=='*')
{
dp[i+1][j]+=dp[i][j]/2;
dp[i+1][j+1]+=dp[i][j]/2;
}
else
{
dp[i+2][j+1]+=dp[i][j];
}
}
}
LL yueshu=zhanzhuan(max,dp[n][m]);
cout<<dp[n][m]/yueshu<<'/'<<max/yueshu<<endl;
}
return 0;
}