【费马小定理求逆元】51nod 1119 LightOJ 1067

费马小定理(Fermat Theory)数论中的一个重要定理,其内容为: 假如p是质数,且gcd(a,p)=1,那么 a(p-1)≡1(mod p)。即:假如a是整数,p是质数,且a,p互质(即两者只有一个公约数1),那么a的(p-1)次方除以p的余数恒等于1。

对于正整数,如果有,那么把这个同余方程中的最小正整数解叫做的逆元。

x = (1/a) (mod p) => ax = 1 (mod p)

a^(p-1) = 1(mod p) => a*a^(p-2) = 1(mod p)

x=a^(p-2)

基准时间限制:1 秒 空间限制:131072 KB 分值: 10  难度:2级算法题
M * N的方格,一个机器人从左上走到右下,只能向右或向下走。有多少种不同的走法?由于方法数量可能很大,只需要输出Mod 10^9 + 7的结果。
Input
第1行,2个数M,N,中间用空格隔开。(2 <= m,n <= 1000000)
Output
输出走法的数量 Mod 10^9 + 7。
Input示例
2 3
Output示例
3
/*
51nod1119
高中组合数学路径问题
https://wenku.baidu.com/view/d14e4482ff00bed5b8f31d28.html
题意:
求C(n+m-2,n-1)%1e9+7
2<=n,m<=1e6

思路:
(n-1)! (m-1)! 跟1e9+7互质
因为数据范围1e6,所以能预处理出n范围内的阶乘
如果数据范围是1e9就gg了
费马小定理求逆元
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL mod=1e9+7;
const int maxn=2e6+10;
LL f[maxn];
void Init()//f[n] 预处理n!
{
    f[0]=1;
    f[1]=1;
    for(int i=1;i<=2e6;i++)
        f[i]=f[i-1]*i%mod;
}
LL quickpow(LL x,LL n)//快速幂x^n
{
    LL ans=1;
    while(n)
    {
        if(n&1)
            ans=(ans*x)%mod;
        x=(x*x)%mod;
        n>>=1;
    }
    return ans;
}

LL C(LL n,LL m)//C(n+m-2,n-1)=(n+m-2)!/(n-1)!*(m-1)!
{
    LL ans=f[n+m-2];
    ans=ans*quickpow(f[n-1],mod-2)%mod;//乘以逆元
    ans=ans*quickpow(f[m-1],mod-2)%mod;
    return ans%mod;
}
int main()
{
    LL n,m;
    Init();
    scanf("%lld%lld",&n,&m);
    printf("%lld\n",C(n,m));
    return 0;
}

/*
LightOJ 1067
题意:
求C(n,m);
1<=n,m<=1e6
gcd((n-m)!,mod)=1 gcd(m!,mod)=1

符合费马小定理的条件
*/
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod=1e6+3;
const int maxn=1e6+10;
LL f[maxn];
void Init()
{
    f[0]=1;
    for(int i=1; i<=1e6; i++)
        f[i]=i*f[i-1]%mod;
}
LL quickpow(LL x,LL n)
{
    LL ans=1;
    while(n)
    {
        if(n&1)
            ans=ans*x%mod;
        x=x*x%mod;
        n>>=1;
    }
    return ans;
}
LL C(LL n,LL m)
{
    LL ans=f[n];
    ans=ans*quickpow(f[m],mod-2)%mod;
    ans=ans*quickpow(f[n-m],mod-2)%mod;
    return ans;
}
int main()
{
    LL n,m;
    int t;
    Init();
    scanf("%d",&t);
    for(int cas=1;cas<=t;cas++)
    {
        scanf("%lld%lld",&n,&m);
        printf("Case %d: %lld\n",cas,C(n,m));
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值