1867: [Noi1999]钉子和小球

来源:互联网 发布:评价莫言诺贝尔 知乎 编辑:程序博客网 时间:2024/05/21 10:53

题目链接

题目大意:给定一个钉子阵,小球从最上方的钉子释放,求到达最底端某个位置的概率

题解:高尔顿钉板实验

我初中还在学语言的时候就见过这个……

这个转移式就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;}