题目大意:给定一个钉子阵,小球从最上方的钉子释放,求到达最底端某个位置的概率
题解:高尔顿钉板实验
我初中还在学语言的时候就见过这个……
这个转移式就naive了
f[i+1][j]+=0.5f[i][j],f[i+1][j+1]+=0.5f[i][j],(i,j)是钉子
f[i+2][j+1]+=f[i][j],(i,j)是空格
但是题目要求分数,重载一下
我的收获:分数运算防卡精度(雾
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int M=55;
int n,m;
bool g[M][M];
struct fra{
ll u,d;
void sim(){
ll t=__gcd(u,d);
u/=t;d/=t;
}
fra(ll a=0,ll b=1){//分母不要设成0……
u=a,d=b;
sim();
}
}f[M][M];
fra operator + (fra A,fra B){//不要重载+=号……
ll t=__gcd(A.d,B.d),l=A.d/t*B.d;
fra res=fra(l/A.d*A.u+l/B.d*B.u,l);
return res;
}
fra operator * (fra A,fra B){
fra res=fra(A.u*B.u,A.d*B.d);
return res;
}
inline bool cread() {
char ch=getchar();
for(;ch!='*'&&ch!='.';ch=getchar());
return ch=='*';
}
void DP()
{
f[1][1]=fra(1,1);
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
if(g[i][j]) f[i+1][j]=f[i+1][j]+f[i][j]*fra(1,2),f[i+1][j+1]=f[i+1][j+1]+f[i][j]*fra(1,2);
else f[i+2][j+1]=f[i+2][j+1]+f[i][j];
}
void work(){
DP();
printf("%lld/%lld", f[n+1][m+1].u,f[n+1][m+1].d);
}
void init(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) for(int j=1;j<=i;j++) g[i][j]=cread();
}
int main()
{
init();
work();
return 0;
}