hdu5698瞬间移动-(杨辉三角+组合数+乘法逆元)

瞬间移动

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2404    Accepted Submission(s): 1066


Problem Description
有一个无限大的矩形,初始时你在左上角(即第一行第一列),每次你都可以选择一个右下方格子,并瞬移过去(如从下图中的红色格子能直接瞬移到蓝色格子),求到第n 行第m 列的格子有几种方案,答案对1000000007 取模。

 

 

Input
多组测试数据。

两个整数n,m(2n,m100000)
 

 

Output
一个整数表示答案
 

 

Sample Input
4 5
 

 

Sample Output
10
 
 
解题过程:
先看一下杨辉三角的图:

矩阵从a【1】【1】开始,先枚举题目的少数答案:

0  0  0  0  0  0  0
1  1  1  1  1  1
1  2  3  4  5  6
1  3  6  10 15 21
0  1  4  10 20 35 56
15 35 70 126
1  6  21 56 126 252 显然斜着看是一个杨辉三角。

 

从左上到右下看作一行一行,从左下到右上数该行第几个。
C(x,y) 斜着看,第x行y个
杨辉三角有效部分可用组合数表示为
(0,0) (1,1) (2,2) (3,3) (4,4) (5,5)
(1,0) (2,1) (3,2) (4,3) (5,4)
(2,0) (3,1) (4,2) (5,3)
(3,0) (4,1) (5,2)
(4,0) (5,1)
(5,0)

 

输入n,m表示n行m列。对应到组合数里。选择杨辉三角部分。
a[n][m]
(2,2) (2,3) (2,4) (2,5) (2,6)
(3,2) (3,3) (3,4) (3,5) (3,6)
(4,2) (4,3) (4,4) (4,5) (4,6)
(5,2) (5,3) (5,4) (5,5) (5,6)
(6,2) (6,3) (6,4) (6,5) (6,6)

 对于从左下到右上这一斜线,n+m相等。
 
将矩形数组a[n][m]和组合数C(x,y)联系起来,我们是利用组合数C(x,y)来算答案,故用x和y表示输入的n和m
对于纵坐标,永远都是y=m-2
对于横坐标,捉摸不定,找出第一列的规律,x=n-2
利用矩阵中n+m相等的条件,推出C(x,y)=C(n+m-4,m-2)。
 
由于n和m巨大,并且题目中的模数p为素数。
求组合数,C(n,m)%p = n! / ( m!*(n-m)! ) %p
用乘法逆元配合快速幂可以解决,本题还不需要用到卢卡斯定理。
 
 AC代码:
 
 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<algorithm>
 4 #include<algorithm>
 5 #include<cstring>
 6 #define ll long long
 7 using namespace std;
 8 const ll p=1e9+7;
 9 
10 ll fact[1000005];
11 
12 void init()
13 {
14     memset(fact,0,sizeof(fact));
15     fact[0]=fact[1]=1;
16     for(ll i=2;i<1000005;i++)
17         fact[i]=fact[i-1]*i%p;
18 
19 }
20 
21 ll power(ll a,ll b,ll p)
22 {
23     ll res=1;
24     while(b)
25     {
26         if(b%2)
27             res=res*a%p;
28         b=b/2;
29         a=a*a%p;
30     }
31     return res%p;
32 }
33 
34 ll C(ll n, ll m ,ll p)
35 {   ///C(n,m) = n! / ( m!*(n-m)! )
36     ///数据太大肯定爆,p又是素数。换成求m!*(n-m)!的逆元,又不能一起求,会爆数据,分开求,看做n!/m! * 1/(n-m)!
37     ///由于是对p求模,n,m范围在阶乘表范围里
38     if(m>n)
39         return 0;
40     return fact[n] * power(fact[m], p-2, p)%p * power(fact[n-m], p-2, p) % p;
41     ///fact * power * power 可能爆long long,第二次就要取模
42 }
43 
44 int main()
45 {
46     init();
47     ll n,m;
48     while(scanf("%lld%lld",&n,&m)!=EOF)
49     {
50         ll ans=C(n+m-4,m-2,p);
51         printf("%lld\n",ans);
52     }
53     return 0;
54 }

 

 
 
posted @ 2019-03-17 10:46  守林鸟  阅读(228)  评论(0编辑  收藏  举报