hdu 5698(杨辉三角的性质+逆元)
---恢复内容开始---
瞬间移动
Accepts: 1018
Time Limit: 4000/2000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
10
注:本文中 C(n,m) 代表了在n个数中取m个数的组合数.
题解:这个题写出前几项之后就应该能够看出是个斜过来的杨辉三角了,杨辉三角的第i行之和为 2^i ,而 2^i又对应了一个二项式展开的系数之和 ,比如 2^n = C(n,1)+C(n,2)+...C(n,n)..然后对应到
我们的图中(见下图),我们会发现行为n,列为m 对应了 2^(n+m-4)这一行,所以我们就可以知道我们要求的点对应的是杨辉三角第 n+m-4 行(这里是从0开始计数),然后根据下图我们也可以得到第我们要求
的第n行是杨辉三角中的第 n-2 行,所以我们可知道 d = (n+m-2)-(n-2) = m-2 ,所以所求结果为第 n+m-4 行中的第 m+2 个数 ,结果自然就是 C(n+m-4,n-2)
然后我们就能 知道 ans = ((n+m-4)!/((n-2)!*(m-2)!))%1000000007 我们可以先打表将所有的阶乘(n+m<2*10^5)求出来,然后求出 (n-2)!*(m-2)!的逆元 inv,结果就为
((n+m-4)!*inv)%1000000007
AC代码:
#include <stdio.h> #include <math.h> #include <iostream> #include <algorithm> #include <string.h> #include <stdlib.h> using namespace std; typedef long long LL; const int mod = 1000000007; const int N = 200005; char str[N]; LL f[N]; LL extend_gcd(LL a,LL b,LL &x,LL &y){ if( b == 0 ) { x = 1; y = 0; return a; } else{ LL x1,y1; LL d = extend_gcd(b,a%b,x1,y1); x = y1; y= x1-a/b*y1; return d; } } LL mod_reverse(LL a,LL n) { LL x,y; LL d=extend_gcd(a,n,x,y); if(d==1) return (x%n+n)%n; else return -1; } void init(){ f[0]=1,f[1] = 1; for(int i=2;i<=N;i++){ f[i] = (f[i-1]*i)%mod; } } int main() { int n,m; init(); while(~scanf("%d%d",&n,&m)){ LL t = f[n-2]*f[m-2]; LL inv = mod_reverse(t,mod); LL ans = (f[n+m-4]*inv)%mod; printf("%d\n",ans); } }
---恢复内容结束---