题目地址:http://www.wikioi.com/problem/2505/
今天找了两道数学题稍微练习了一下。。。
这一道比较水。
这是一道递推的经典例题的数据加强版。。。但因为数据范围太大,明显不用递推。。。
然后,这道题也是一道组合的经典例题:
根据题意,小A一共要走m+n步,其中有n步是横着在走。。。可以想到,每一种走法都是在这m+n步中选择不同的n步作为横着走的情况。。。。实际上就是组合数C(m+n,n).
现在关键问题就是这个m+n怎么算。首先明确的是一定要用高精度。
对于组合数的计算,可以用C(n,r)=C(n-1,r)+C(n-1,r-1)这个公式。。。但是其实这样复杂度是比较高的,并不适用
那怎么办?。。套公式即可。。。只不过不能硬算阶乘,要边乘边除。(相当于用C(n,r+1)=C(n,r)*(n-k)/(k+1)这个公式从C(n,0)开始推)
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=10000000;
struct bign
{
long long num[2000],len;
bign()
{
memset(num,0,sizeof(num));
len=1;
}
bign operator =(int x)
{
len=0;
while(x)
{
num[len++]=x%M;
x/=M;
}
if(len==0)len=1;
return *this;
}
bign operator =(const bign &b)
{
len=b.len;
for(int i=0;i<len;i++)num[i]=b.num[i];
return *this;
}
bign operator *(int x)
{
bign c;
c.len=len;
for(int i=0;i<len;i++)
{
c.num[i]=x*num[i];
}
long long temp=0;
for(int i=0;i<c.len;i++)
{
c.num[i]+=temp;
temp=c.num[i]/M;
c.num[i]=c.num[i]%M;
if(i==c.len-1&&temp!=0)
{
c.len++;
}
}
return c;
}
bign operator /(int x)
{
bign c;
c.len=len;
long long temp=0;
for(int i=len-1;i>=0;i--)
{
temp*=M;
temp+=num[i];
if(temp>x)
{
c.num[i]=temp/x;
temp-=c.num[i]*x;
}
}
while(c.len&&c.num[c.len-1]==0)c.len--;
if(c.len==0)c.len=1;
return c;
}
void print()
{
printf("%d",num[len-1]);
for(int i=len-2;i>=0;i--)printf("%07lld",num[i]);
printf("\n");
}
};
int N,m;
bign C(int n,int k)
{
bign ret;
ret=1;
for(int i=1;i<=k;i++)
{
ret=ret*(n-i+1)/i;
}
return ret;
}
int main()
{
scanf("%d%d",&N,&m);
bign ans;
ans=C(N-1+m-1,min(N-1,m-1));
ans.print();
return 0;
}