【题解】BZOJ P1867 dp

这题其实并不是在考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]


 

然而难点不在dp,在分数输出好吧!

来自交了n遍才乱搞对的蒟蒻

我用了一种非常科学的做法

众所周知,小球在每个位置的平均概率是2ˆn

所以我们正常算出f[n+1][m+1]后再让它和2ˆn搞一个gcd,将两数同时除以gcd(相当于约分)即可


 

code

#include<bits/stdc++.h>
#define ll long long
using namespace std;
namespace gengyf{
ll n,m,f[55][55],tot,ans;
char mp[55][55];
ll gcd(ll x,ll y){
    if(!y) return x;
    return gcd(y,x%y);
}
ll power(ll x,ll y){
    ll q=1;
    while(y){
        if(y%2)
            q*=x;
        y/=2;
        x=x*x;
    }
    return q;
}
int main(){
    scanf("%lld%lld",&n,&m);
    tot=power(2,n);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=i;j++)
            scanf("%s",&mp[i][j]);
    f[1][1]=tot;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=i;j++){
            if(mp[i][j]=='*')
                f[i+1][j]+=f[i][j]/2,f[i+1][j+1]+=f[i][j]/2;
            else
                f[i+2][j+1]+=f[i][j];
        }
    }
    ans=gcd(tot,f[n+1][m+1]);
    f[n+1][m+1]/=ans,tot/=ans;
    printf("%lld/%lld\n",f[n+1][m+1],tot);
    return 0;
}
}
int main(){
    gengyf::main();return 0;
}

 

posted @ 2019-07-17 21:30  喵の耳  阅读(187)  评论(0编辑  收藏  举报