HDU5698 瞬间移动(求逆元)

Problem Description

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

Input

多组测试数据。

两个整数n,m(2≤n,m≤100000)

Output

一个整数表示答案

Sample Input

4 5

Sample Output

10

思路

我们要从 (1,1) ( 1 , 1 ) 点走到 (n,m) ( n , m ) 点,只能向右下角的格子里走,那么 (1,1) ( 1 , 1 ) 所在的行和列不能走, (n,m) ( n , m ) 所在的行和列不能走,那么能走的面积就是 (n2)(m2) ( n − 2 ) ∗ ( m − 2 ) 这么大的面积,行和列分别考虑,实质上就是求组合数 Cn2(n2)+(m2) C ( n − 2 ) + ( m − 2 ) n − 2

因为 Cmn=n!m!(nm)! C n m = n ! m ! ∗ ( n − m ) ! ,乘以一个数等于乘这个数的逆元,我们先预处理出阶乘的逆元。

首先求出一个数模p的逆元:

f[i]=(ppi)f[p%i]%p f [ i ] = ( p − p i ) ∗ f [ p % i ] % p

然后再递推出 n! n ! 的逆元
inv[(n1)!]=inv[n!]n%p i n v [ ( n − 1 ) ! ] = i n v [ n ! ] ∗ n % p

可以得到
inv[n!]=inv[(n1)!]f[n]%p i n v [ n ! ] = i n v [ ( n − 1 ) ! ] ∗ f [ n ] % p

然后就可以求出组合数了

代码

#include 
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const ll N=200000+20;
ll fac[N]= {1,1},inv[N]= {1,1},f[N]= {1,1};
/*
fac[i]:i的阶乘
inv[i]:i的阶乘的逆元
f[i]:i的逆元
*/
ll C(ll a,ll b)//除以一个数等于乘这个数的逆元
{
    return fac[a]*inv[b]%mod*inv[a-b]%mod;
}
void init()
{
    for(ll i=2; i1]*i%mod;
        f[i]=(mod-mod/i)*f[mod%i]%mod;
        inv[i]=inv[i-1]*f[i]%mod;
    }
}

int main()
{
    ll n,m;
    init();
    while(cin>>n>>m)
        cout<4,m-2)<return 0;
}

你可能感兴趣的:(【数论,欧拉函数,逆元,卢卡斯定理】)