【GDOI2014模拟】网格
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
反思&题解
比赛思路: 刚看以为是送分题,果断DP,设
表示走到点
时总共的步数,显然方程为:
;后来看了一下空间,WOC才65536KB,不过开个滚动马上解决,结果测了个极限数据,发现unsigned long long也会爆,之后打了个高精度,过了样例,信心满满地测了个极限数据,结果T飞了……后来发现当
时答案就是卡特兰数的第n位,但是因为我不会
构造卡特兰数,于是拿不到特殊数据的50分……
正解思路: 根据一堆图示推算可以得到答案为:
,详细推算过程见这篇大佬的博客(我太懒了就不写在这了)
其实直接套这个式子打高精度就能过了,但我相信一定有朋友跟我一样不想打高精度除法,那么现在我来讲一种好的方法:
首先我们将原式化简一下:
好的,到这里就够了,看到了一条除号(分数线),这时候我们肯定会下意识想到分解质因数!因为答案肯定是一个整数,所以这个式子的分母的所有质因数肯定分子里面也有(这个不难证明吧),所以我们只需要将分子的每一项先分解质因数,之后再把分母的每一项分解质因数,去重之后乘上没有重复的质因数就行了
反思: 数学思维要加强,有时候可以画图找找规律,不过我觉得以初一中游水平的数学考场上想出这题还是有(gen)很(ben)大(bu)很(ke)难(neng)度(de)
CODE
#include<bits/stdc++.h>
using namespace std;
int zyz[10005],n,m,tot,ans[10005];
void cheng(int num)
{
int x=0,i;
for (i=1;i<=ans[0];i++)
{
ans[i]=ans[i]*num+x;
x=ans[i]/10;
ans[i]%=10;
}
while (x>0)
{
ans[++ans[0]]=x%10;
x/=10;
}
}
int main()
{
scanf("%d%d",&n,&m);
int i;
int n1=n-m+1,n2=n1;
for (i=2;i<=n2;i++)
{
if (n1==1) break;
while (n1%i==0)
{
zyz[i]++;
n1/=i;
}
}
int j;
for (j=1;j<=m+n;j++)
{
n1=j;
n2=n1;
for (i=2;i<=n2;i++)
{
if (n1==1) break;
while (n1%i==0)
{
zyz[i]++;
n1/=i;
}
}
}
for (j=1;j<=m;j++)
{
n1=j;
n2=n1;
for (i=2;i<=n2;i++)
{
if (n1==1) break;
while (n1%i==0)
{
zyz[i]--;
n1/=i;
}
}
}
for (j=1;j<=n+1;j++)
{
n1=j;
n2=n1;
for (i=2;i<=n2;i++)
{
if (n1==1) break;
while (n1%i==0)
{
zyz[i]--;
n1/=i;
}
}
}
ans[0]=1;
ans[1]=1;
for (i=2;i<=n+m;i++)
{
if (zyz[i]>0)
{
for (j=1;j<=zyz[i];j++)
cheng(i);
}
}
for (i=ans[0];i>=1;i--)
printf("%d",ans[i]);
printf("\n");
return 0;
}