瞬间移动
Source
分析:
画几个数之后就可以发现规律了,可以看出是一个倾斜45度的杨辉三角,每个位置的的数相当于:从杨辉三角第(n+m-4)层,取m-2个数。
因为会有除法取模,所以要用逆元。
有两个公式:
这两个公式实际上是等价的,只是用代码实现的时候会有所差别。
我是用第二个写的:
#include<cstdio>
#include<cstring>
const long long mod=1000000007;
typedef long long ll;
const int N=100002;
ll inv[N];
int main()
{
int n,m;
inv[1]=1;
for(int i=2;i<N;i++)inv[i]=(mod-mod/i)*inv[mod%i]%mod;
while(~scanf("%d%d",&n,&m)){
if(n==1||m==1){
printf("0\n");continue;
}
n=n+m-4;
m=m-2;
ll ans=1;
for(int i=1;i<=m;i++){
ans=(ans*(ll)(n-i+1))%mod;
ans=(ans*inv[i])%mod;
}
printf("%lld\n",ans);
}
return 0;
}
当然逆元也有很多种实现方法:
可以用扩展欧几里德定理,费马小定理(这需要快速幂实现),或者上面那个递推公式。
对于这题,是用杨辉三角来做的,也有人的思路是:
给我们一个坐标,我们可以得出可以移动到的区域即(n-2)*(m-2)。枚举要在这个区域停留几次,C(y,k),表示从y列中选k列去停,C(x,k)表示从x行中选哪k行去停。所以乘积累加即为结果。
这种《问题分解》的思想是值得学习的,就像UVa 11134这题的思想是一致的。