【Description】
有一个三角形木板,竖直立放,上面钉着n(n+1)/2颗钉子,还有(n+1)个格子(当n=5时如图1)。每颗钉子和周围的钉子的距离都等于d,每个格子的宽度也都等于d,且除了最左端和最右端的格子外每个格子都正对着最下面一排钉子的间隙。
让一个直径略小于d的小球中心正对着最上面的钉子在板上自由滚落,小球每碰到一个钉子都可能落向左边或右边(概率各1/2),且球的中心还会正对着下一颗将要碰上的钉子。例如图2就是小球一条可能的路径。
现在的问题是计算拔掉某些钉子后,小球落在编号为m的格子中的概率pm。假定最下面一排钉子不会被拔掉。例如图3是某些钉子被拔掉后小球一条可能的路径。
【Input】
第1行为整数n(2<=n<=50)。
以下n行依次为木板上从上至下n行钉子的信息,每行中‘*’表示钉子还在,‘.’ 表示钉子被拔去(最下面一排的钉子不会拔掉),注意在这n行中空格符可能出现在任何位置。
【Output】
共n+1行,每一行是一个既约分数(0写成0/1),为小球落在编号为0到编号为n这n+1个的格子中的概率m。
既约分数的定义:A/B是既约分数,当且仅当A、B为正整数且A和B没有大于1的公因子。
【Sample Input】
4
*
* *
* . *
* * * *
【Sample Output】
1/16
1/8
5/8
1/8
1/16
【题解】
动态转移方程:
f(i,j)=⎧⎩⎨⎪⎪⎪⎪f(i,j)+f(i−1,j−1)2f(i,j)+f(i−1,j)2 f(i,j)+f(i−2,j−1)i−1行j−1列为∗i−1行 j 列为∗i−2行j−1列为.
(另:pascal在计算 2n 时,如果变量类型为 int64 ,使用左移操作易出错)
参考代码如下:
var c:char;
f:array[0..52,0..52] of int64;
i,j,n:longint;
tmp,t:int64;
begin
readln(n); t:=1;
for i:=1 to n do t:=t*2; f[1,1]:=t; //初始化
for i:=1 to n do begin
for j:=1 to i do begin
read(c); while (c=' ') do read(c); //处理空格
if c='*' then begin
inc(f[i+1,j],f[i,j] shr 1); inc(f[i+1,j+1],f[i,j] shr 1);
end
else inc(f[i+2,j+1],f[i,j]);
end;
readln;
end;
for i:=1 to n+1 do
if f[n+1,i]=0 //分类输出
then writeln('0/1')
else begin
tmp:=t;
while (f[n+1,i] mod 2=0) do begin
f[n+1,i]:=f[n+1,i] shr 1; tmp:=tmp shr 1;
end;
writeln(f[n+1,i],'/',tmp);
end;
end.