题目

题目背景

LYQ市有一个巨大的水沟网络,可以近似看成一个n*m的矩形网格,网格的每个格点都安装了闸门,我们将从水沟网络右下角的闸门到左上角的闸门的一条路径称为水流。

题目描述

现给定水沟网的长和宽,求该水沟网中所有只包含向左和向上移动的水流数量。

输入输出格式

输入格式:

输入共1行,包含两个整数n和m。

输出格式:

输出一个数字ans,即水流的数量。由于答案可能很大,请输出答案对1000000007取模的结果。

分析:

由题意推理得:

C n + m n = ( n + m ) ! n ! m ! C^{n}_{n+m}=\frac{(n+m)!}{n!m!} Cn+mn=n!m!(n+m)!

但是我们看一下数据范围: n , m &lt; = 1000000 n,m&lt;=1000000 n,m<=1000000

妈呀,这样咋除呀。

这个时候我们就要引入一个东东:

乘法逆元

说白了一个数的乘法逆元就是他的倒数。。。

其他百度一下就行。

用乘法逆元有啥好处?

ans:可以再弄个费马小定理后用快速幂迅速解决。

那么快速幂是啥?

就比如说 3 9 = 3 8 3 = 3 2 2 3 3 4 3^9=3^8*3={3^2}^2*3*3^4 39=383=322334等等减少运算次数的,仍可百度。

那么主要思路就出来了:把推出的那个 C n + m n = ( n + m ) ! n ! m ! C^{n}_{n+m}=\frac{(n+m)!}{n!m!} Cn+mn=n!m!(n+m)!的除号下面的部分转换为他的逆元,通过费马小定理写出幂的形式,然后用快速幂迅速求出。

上代码

代码:

#include<cstdio>
const int mod=1000000007;
long long f(long long n) //计算一波阶乘 
{
    long long sum=1;
    for(long long i=1;i<=n;i++) 
	sum=sum*i%mod;
    return sum;
}
long long pow(long long n,long long p)//快速幂 
{
    if(!p)//a^0=1 (a!=0) 
 		return 1;
    long long tmp=pow(n,p>>1)%mod;
    if(p&1) //即判断是否p%2==1 
		return tmp*tmp%mod*n%mod;
    else 
		return tmp*tmp%mod;
}
long long inv(long long x) 
{ 
    return pow(x,mod-2);//取其逆元,费马小定理 
}
int main() 
{
    int n,m;
    scanf("%d%d",&n,&m);
    printf("%d",(int)(f(n+m)*inv(f(n))%mod*inv(f(m))%mod));//计算公式: 
    return 0;
}

求关注