3907: 网格
Time Limit: 1 Sec Memory Limit: 256 MBSubmit: 398 Solved: 178
[ Submit][ Status][ Discuss]
Description
某城市的街道呈网格状,左下角坐标为A(0, 0),右上角坐标为B(n, m),其中n >= m。现在从A(0, 0)点出发,只能沿着街道向正右方或者正上方行走,且不能经过图示中直线左上方的点,即任何途径的点(x, y)都要满足x >= y,请问在这些前提下,到达B(n, m)有多少种走法。
![](http://www.lydsy.com/JudgeOnline/upload/201503/ff1%281%29.png)
Input
输入文件中仅有一行,包含两个整数n和m,表示城市街区的规模。
Output
输出文件中仅有一个整数和一个换行/回车符,表示不同的方案总数。
Sample Input
6 6
Sample Output
132
HINT
100%的数据中,1 <= m <= n <= 5 000
Source
题解:卡特兰数+组合数学+高精度
这道题相当于经典的购票问题。
最后的答案是C(n+m,n)-C(n+m,n+1)
这里有一些有关卡特兰数问题的讲解:http://blog.csdn.net/wuyuegb2312/article/details/9339529
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 10003
using namespace std;
struct data {
int s[N],len;
data (){
memset(s,0,sizeof(s));
len=0;
}
}ans,ans1;
int n,m,prime[N],mp[N],pd[N],num[N];
void init()
{
for (int i=2;i<=10000;i++) {
if (!pd[i]) prime[++prime[0]]=i,mp[i]=prime[0];
for (int j=1;j<=prime[0];j++) {
if (prime[j]*i>10000) break;
pd[prime[j]*i]=1;
if (i%prime[j]==0) break;
}
}
}
void calc(int x,int val)
{
int k=x;
for (int i=1;prime[i]*prime[i]<=k;i++)
if (k%prime[i]==0) {
while (k%prime[i]==0)
num[i]+=val,k/=prime[i];
}
if (k>1) num[mp[k]]+=val;
}
data mul(data a,int x)
{
data c; int t=a.len;
for (int i=1;i<=a.len;i++)
c.s[i]=a.s[i]*x;
for (int i=1;i<=t;i++) {
c.s[i+1]+=c.s[i]/10;
c.s[i]%=10;
}
while (c.s[t+1]) {
t++; c.s[t+1]+=c.s[t]/10;
c.s[t]%=10;
}
c.len=t;
return c;
}
data jian(data a,data b)
{
data c;
int t=a.len;
for (int i=1;i<=t;i++) c.s[i]=a.s[i]-b.s[i];
for (int i=1;i<=t;i++)
if (c.s[i]<0) c.s[i]+=10,c.s[i+1]--;
while (!c.s[t]) t--;
c.len=t;
return c;
}
int main()
{
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%d%d",&n,&m);
init();
for (int i=n+1;i<=n+m;i++) calc(i,1);
for (int i=1;i<=m;i++) calc(i,-1);
ans.len=ans.s[1]=1;
for (int i=1;i<=prime[0];i++)
while (num[i]) ans=mul(ans,prime[i]),num[i]--;
//for (int i=ans.len;i>=1;i--) printf("%d",ans.s[i]);
//printf("\n");
for (int i=m;i<=n+m;i++) calc(i,1);
for (int i=1;i<=n+1;i++) calc(i,-1);
ans1.len=ans1.s[1]=1;
for (int i=1;i<=prime[0];i++)
while (num[i])
ans1=mul(ans1,prime[i]),num[i]--;
//for (int i=ans1.len;i>=1;i--) printf("%d",ans1.s[i]);
//printf("\n");
ans=jian(ans,ans1);
for (int i=ans.len;i>=1;i--) printf("%d",ans.s[i]);
printf("\n");
}