利用逆元对除法运算进行取模操作(Gym - 101775A )

首先说明逆元的概念,类似于倒数的性质。(这里只给出费马小定理求取逆元)

方程ax≡1(mod p),的解称为a关于模p的逆,当gcd(a,p)==1(即a,p互质)时,方程有唯一解,否则无解。

对于一些题目会要求把结果MOD一个数,通常是一个较大的质数,对于加减乘法通过同余定理可以直接拆开计算,

但对于(a/b)%MOD这个式子,是不可以写成(a%MOD/b%MOD)%MOD的,但是可以写为(a*b^-1)%MOD,其中b^-1表示b的逆元。

知道了逆元的作用,接下来就是逆元的求法。

首先,有一个费马小定理:

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

意思很明了,由上方的公式很容易推导出:a*a(p-2)≡1(mod p)对于整数a,p,a关于p的逆元就是a^(p-2),直接快速幂解之即可,但注意这个定理要求a,p互质!

大体的模板就是:(a/b)%mod = a%mod * pow(b,mod-2)%mod;

题目链接:https://vjudge.net/problem/Gym-101775A
下面直接给出例题,根据题目具体理解模板:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int mod=1000000007;
const int maxn = 1e5 + 10;
ll N,k;

ll mod_pow(ll x,ll n)
{
    ll res=1;
    while(n>0)
    {
        if(n&1) res=res * x % mod;
        x=x * x % mod;
        n >>= 1;
    }
    return res;
}
ll c(ll n,ll k)
{
    ll sum = 1,ans=1;
    for(ll i=1; i<k; i++)
    {

        ans=ans *(n-i+1)%mod*mod_pow(i,mod-2)%mod;
        sum+=ans;
        sum%=mod;
        //cout<<"fdsfa   "<<sum<<endl;
    }
    return sum;
}

int main()
{
    int T,kase = 1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%I64d %I64d",&N,&k);
        ll sum = mod_pow(2,N);
        //cout<<"fdsaffdsa    "<<sum<<endl;
        sum = (sum-c(N,k)+mod)%mod;
        printf("Case #%d: %I64d\n",kase++,sum);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/NCC__dapeng/article/details/82385374