zoukankan      html  css  js  c++  java
  • 【HDU 5698】 瞬间移动

    【题目链接】

               点击打开链接

    【算法】

              用f[i][j]表示走到(i,j)这个位置有多少种方案,因为走到(i,j)这个位置,上一步一定在它左上角的矩形中,所以,

              f(i,j) = sigma( f(x,y) ) ( (x,y)在左上角的矩形中) 

              我们尝试将它画出来,发现是斜着的杨辉三角

              然后,通过找规律,我们发现 : f(n,m) = C(n+m-4,n-2) 

              求C函数的值,这里有一种方法 :

               C(n,r) mod P = (n! / (n - r)! / r!) mod P

                                    = (n!) mod P * inv( (n - r)! ) mod P * inv( r! ) mod P( 其中,inv表示乘法逆元 )

               考虑预处理阶乘和阶乘逆元

               阶乘很容易求,那么,阶乘逆元怎么求呢?

               这里有一种线性求阶乘逆元的方法 ( 如果我们要求 inv( n! ) ) :

               inv(n ! ) = inv( (n - 1)! n )

                            = inv( (n - 1)! ) inv( n )

               所以 inv( (n - 1)! ) = inv( n ! ) * inv( inv( n ) )

                                            = inv( n! ) * n

               有了这个式子,我们便可以在线性时间内求出所有的阶乘逆元

               这一题,我们只要预处理阶乘和阶乘逆元,然后,O(1)回答询问,即可

    【代码】

               

    #include<bits/stdc++.h>
    using namespace std;
    #define MAXN 200010
    const long long P = 1000000007;
    
    long long n,m;
    long long fac[MAXN],inv[MAXN];
    
    inline long long power(long long a,long long n)
    {
            long long ans = 1,b = a;
            while (n > 0)
            {
                    if (n & 1) ans = (ans * b) % P;
                    b = (b * b) % P;
                    n >>= 1;
            }
            return ans;
    }
    inline void init()
    {
            int i;
            fac[0] = 1;
            for (i = 1; i < MAXN; i++) fac[i] = fac[i-1] * i % P;
            inv[MAXN-1] = power(fac[MAXN-1],P-2);
            for (i = MAXN - 2; i >= 1; i--) inv[i] = inv[i+1] * (i + 1) % P;
    }
    inline long long C(long long n,long long m)
    {
            if (!m) return 1;
            else if (n == m) return 1;
            else return fac[n] * inv[n-m] % P * inv[m] % P;    
    }
    
    int main() {
            
            init();
            while (scanf("%d%d",&n,&m) != EOF)
            {
                    printf("%lld
    ",C(n+m-4,n-2));    
            }
            
            return 0;
        
    }
    
    /*
      f( n! ) = f( (n-1)! n) = f( (n - 1)! ) f(n)
      f( n! ) * f( f(n) ) = f( (n - 1)! )
        f( n! ) * n = f( (n - 1)! )
        f( n! ) = f ( (n + 1)! ) * (n + 1)
    */ 
  • 相关阅读:
    SVN服务器搭建(一)
    排序算法二:冒泡排序
    【LeetCode】136. Single Number
    【LeetCode】217. Contains Duplicate
    【LeetCode】189. Rotate Array
    【LeetCode】122. Best Time to Buy and Sell Stock II
    【LeetCode】26. Remove Duplicates from Sorted Array
    【LeetCode】20. Valid Parentheses
    【LeetCode】680. Valid Palindrome II
    【LeetCode】345. Reverse Vowels of a String
  • 原文地址:https://www.cnblogs.com/evenbao/p/9196304.html
Copyright © 2011-2022 走看看