zoukankan      html  css  js  c++  java
  • 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
    ",ans);
    52     }
    53     return 0;
    54 }
     
     
  • 相关阅读:
    leetcode 78. 子集 JAVA
    leetcode 91. 解码方法 JAVA
    leetcode 75. 颜色分类 JAVA
    leetcode 74 搜索二维矩阵 java
    leetcode 84. 柱状图中最大的矩形 JAVA
    last occurance
    first occurance
    classical binary search
    LC.234.Palindrome Linked List
    LC.142. Linked List Cycle II
  • 原文地址:https://www.cnblogs.com/shoulinniao/p/10545193.html
Copyright © 2011-2022 走看看