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)
    */ 
  • 相关阅读:
    关于webpack升级过后不能打包的问题;
    数组的一些理解
    .NET(C#):使用Win32Exception类型处理Win32错误代码
    托管代码和非托管代码
    托管DLL和非托管DLL的区别
    C#实现Dll(OCX)控件自动注册的两种方法(转)
    Com组件和Dll文件区别
    C#创建COM组件
    ajaxFileUpload插件上传文件 返回 syntaxError :unexpected token
    jquery插件--ajaxfileupload.js上传文件原理分析
  • 原文地址:https://www.cnblogs.com/evenbao/p/9196304.html
Copyright © 2011-2022 走看看