Description
某城市的街道呈网格状,左下角坐标为A(0, 0),右上角坐标为B(n, m),其中n >= m。现在从A(0, 0)点出发,只能沿着街道向正右方或者正上方行走,且不能经过图示中直线左上方的点,即任何途径的点(x, y)都要满足x >= y,请问在这些前提下,到达B(n, m)有多少种走法。
Input
输入文件中仅有一行,包含两个整数n和m,表示城市街区的规模。
Output
输出文件中仅有一个整数和一个换行/回车符,表示不同的方案总数。
Sample Input
输入1:
6 6
输入2:
5 3
Sample Output
输出1:
132
输出2:
28
Data Constraint
50%的数据中,n = m,在另外的50%数据中,有30%的数据:1 <= m < n <= 100
100%的数据中,1 <= m <= n <= 5 000
Solution
首先可以得出,从(0,0)不加那条限制的线走到(x,y)的方案为
Cyx+y
那么将限制的线向上平移一个单位,限制就是不能碰到线。那么加上限制的方案数就是不加限制走到(x,y)-不加限制走到(x,y)关于平移后的线的对称点。因为走到对称点的线必定碰到了这条线。那么方案就是
Cyx+y−Cy−1x+y
那么按照公式做高精度就行了。
不过有一种稍微简单点的方法,就只要打高精度乘或除单精度。
先把公式化简,变成
(n+m)!∗(n+1−m)/((n+1)!∗m!)
先把
∗(n+1−m)
丢一边去,那么分母就是
(n+1)!∗m!
,显然前面那个大一点,那就先和上面约掉变成
(n+2)∗(n+3)∗……∗(n+m)
这里乘数的每一个都是单精度,然后除的时候分别除1,除2,……除m,最后再乘上丢掉的那个东西,就行了。
type arr=array[0..100000] of int64;
var
i,j,k,n,m:longint;
mo:int64=1000000;
ans:arr;
function min(a,b:longint):longint;begin if a<b then exit(a)else exit(b);end;
procedure cheng(var a:arr;b:int64);
var
i:longint;
c:arr;
begin
fillchar(c,sizeof(c),0);
for i:=1 to a[0] do
begin
a[i]:=a[i]*b+c[i];
if a[i]>mo then
begin
c[i+1]:=c[i+1]+(a[i] div mo);a[i]:=a[i] mod mo;
if c[i+1]>mo then begin c[i+2]:=c[i+2]+(c[i+1] div mo);c[i+1]:=c[i+1]mod mo;end;
end;
end;
while c[a[0]+1]<>0 do begin inc(a[0]);a[a[0]]:=c[a[0]];end;
end;
procedure chu(var a:arr;b:int64);
var
i:longint;
c,d:int64;
begin
c:=0;
for i:=a[0] downto 1 do
begin
d:=(a[i]+c)mod b;
a[i]:=(a[i]+c) div b;c:=d*mo;
end;
while (a[a[0]]=0) do dec(a[0]);
end;
procedure printf(a:arr);
var
i,j:longint;
s:string;
begin
write(a[a[0]]);
for i:=a[0]-1 downto 1 do
begin
str(a[i],s);
for j:=length(s)+1 to 6 do write(0);
write(a[i]);
end;
writeln;
end;
begin
read(n,m);ans[0]:=1;ans[1]:=1;
for i:=n+2 to n+m do cheng(ans,i);
cheng(ans,n+1-m);
for i:=2 to m do chu(ans,i);
printf(ans);
end.