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 }
     
     
  • 相关阅读:
    go---weichart个人对Golang中并发理解
    go语言值得学习的开源项目推荐
    mysql17---增量备份
    mysql16---读写分离
    mysql15--垂直分表水平分表
    mysql14---手动备份
    mysql13---索引使用注意
    mysql12----explain
    mysql11---主键普通全文索引
    OpenOffice的简单安装
  • 原文地址:https://www.cnblogs.com/shoulinniao/p/10545193.html
Copyright © 2011-2022 走看看