[bzoj1867][Noi1999][钉子和小球] (动态规划)
Description
Input
第1行为整数n(2<=n<=50)和m(0<=m<=n)。以下n行依次为木板上从上至下n行钉子的信息,每行中‘*’表示钉子还在,‘.’表示钉子被拔去,注意在这n行中空格符可能出现在任何位置。
Output
仅一行,是一个既约分数(0写成0/1),为小球落在编号为m的格子中的概pm。既约分数的定义:A/B是既约分数,当且仅当A、B为正整数且A和B没有大于1的公因子。
Sample Input
5 2
Sample Output
7/16
Solution
设f[i][j]代表小球落到位置为(i,j)的概率,分数求解即可
#include <stdio.h> #define L long long #define RG register inline void Rin(RG int &x) { x=0;RG int c=getchar(),f=1; for(;c<48||c>57;c=getchar()) if(!(c^45))f=-1; for(;c>47&&c<58;c=getchar()) x=(x<<1)+(x<<3)+c-48; x*=f; } inline void ploy(RG bool &x) { RG char c=getchar(); while(c!='*'&&c!='.')c=getchar(); x=c=='*'?true:false; } void Shiki(RG L x) { if(!x)return; Shiki(x/10); putchar(x%10+48); } L gcd(RG L a,RG L b) { return b?gcd(b,a%b):a; } bool _map[55][55]; int n,m; struct fr{ L n,d; fr(RG L _=0,RG L __=1) : n(_),d(__) {} }f[55][55]; inline void rec(fr &_this) { L t=gcd(_this.n,_this.d); _this.n/=t; _this.d/=t; } fr operator + (const fr &a,const fr &b) { fr res; L t=gcd(a.d,b.d); res.n=b.d/t*a.n+a.d/t*b.n; res.d=a.d/t*b.d; return res; } fr operator * (const fr &a,const fr &b) { fr res(a.n*b.n,a.d*b.d); rec(res); return res; } void operator += (fr &a,const fr &b) { a=a+b; } int main() { Rin(n),Rin(m); for(RG int i=1; i<=n; i++) for(RG int j=1; j<=i; j++) ploy(_map[i][j]); f[1][1]=fr(1,1); for(RG int i=1; i<=n; i++) for(RG int j=1; j<=i; j++) rec(f[i][j]), _map[i][j]? f[i+1][j]+=f[i][j]*fr(1,2),f[i+1][j+1]+=f[i][j]*fr(1,2): f[i+2][j+1]+=f[i][j]; rec(f[n+1][m+1]); Shiki(f[n+1][m+1].n); putchar('/'); Shiki(f[n+1][m+1].d); return 0; }