[BZOJ 1867][NOI 1999]钉子和小球(DP水题)

题目链接

http://www.lydsy.com/JudgeOnline/problem.php?id=1867

思路

f[i][j] 代表小球落到第 i 行第 j 个格子上的概率。很容易得到DP方程

f[i+1][j]+=12f[i][j],f[i+1][j+1]+=12f[i][j],(i,j)

f[i+2][j+1]+=f[i][j],(i,j)

f[1][1]=1

然后写个恶心的分数结构体就行了,注意有个坑点:分数在通分时可能爆long long!

代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#define MAXN 60

using namespace std;

typedef long long int LL;

LL gcd(LL a,LL b)
{
    if(!b) return a;
    return gcd(b,a%b);
}

struct Fraction
{
    LL up,dn;
    //Fraction(){ up=0,dn=1; } //!!!
    Fraction(LL _up=0,LL _dn=1):up(_up),dn(_dn){}
    void reduction()
    {
        LL t=gcd(up,dn);
        up/=t,dn/=t;
    }
    void print()
    {
        cout<<up<<'/'<<dn;
    }
}f[MAXN][MAXN];

Fraction operator*(Fraction a,Fraction b)
{
    Fraction c=Fraction(a.up*b.up,a.dn*b.dn);
    c.reduction();
    return c;
}

Fraction operator+(Fraction a,Fraction b)
{
    LL t=gcd(a.dn,b.dn);
    Fraction c=Fraction(b.dn/t*a.up+a.dn/t*b.up,a.dn/t*b.dn);
    c.reduction();
    return c;
}

int n,m;
char map[MAXN][MAXN];

char getch()
{
    char ch=getchar();
    while(ch==' '||ch=='\n'||ch=='\r'||ch=='\t') ch=getchar();
    return ch;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=i;j++)
            map[i][j]=getch();
    f[1][1]=Fraction(1,1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            if(map[i][j]=='*')
                f[i+1][j]=f[i+1][j]+f[i][j]*Fraction(1,2),f[i+1][j+1]=f[i+1][j+1]+f[i][j]*Fraction(1,2);
            else
                f[i+2][j+1]=f[i+2][j+1]+f[i][j];
        }
    f[n+1][m+1].print();
    return 0;
}

你可能感兴趣的:([BZOJ 1867][NOI 1999]钉子和小球(DP水题))