逆元的应用

简介: 逆元的应用

1.逆元解释:

逆元定义:

来自一个大佬的通俗解释:

逆元基本应用1

我们知道对于取余运算,有以下性质:

但是唯独除法是不满足的!

现证明除法不满足:

而对于一些题目,我们必须在中间过程中进行求余,否则数字太大,电脑存不下,那如果这个算式中出现除法,我们就需要逆元了

现在就要在回到刚才的问题了,除以一个数等于乘上这个数的倒数,在除法取余的情况下,就是乘上这个数的逆元

这样就把除法,完全转换为乘法了!

逆元的五种求法

1.暴力求解,易理解但是时间复杂度巨大,上代码:

int Inverse_element(int a, int p)
{
    a = a % p;
    int flag = 0;
    int result;
    for (int i = 1; i < 100000; i++)
    {
        flag = 0;
        for (int j = 1; j < 100000; j++)
        {
            if (a * i == 1 + p * j)
            {
                result = i;
                flag = 1;
                break;
            }
        }
        if (flag == 1)
        {
            break;
        }
    }
    return result;
}

2.扩展欧几里得算法

扩展欧几里得算法定义:

模数可以不为质数,满足gcd(a,b)=1即可:

当gcd(a,b)=1时,代入extend_gcd(a,b,x,y),得到的非负的x值,就是上面的a-1

时间复杂度O ( l o g ( n ) ) O(log(n))O(log(n))

ll exgcd(ll a, ll b, ll &x, ll &y)
{
  if (b == 0)
  {
    x = 1, y = 0;
    return a;
  }
  ll d, x1, y1;
  d = exgcd(b, a % b, x1, y1);
  x = y1;
  y = x1 - a / b * y1;
  return d;
}
ll inverse(ll a, ll b, ll &x, ll &y)
{
  if (__gcd(a, b) != 1) return -1;
  else
  {
    exgcd(a, b, x, y);
    return (x % b + b) % b;
  }
}

3.欧拉定理和费马小定理:

欧拉定理在数论中,欧拉定理,(也称费马-欧拉定理)是一个关于同余的性质。欧拉定理表明,若n,a为正整数,且n,a互质,则:

φ(n)为欧拉函数(1 − n 中 与 n 互 质 的 数 的 个 数 。 1-n中与n互质的数的个数。1nn(1与任何数互质))。

费马小定理:(只适用于模数为质数的情况 )

n nn为质数且a不为n的倍数时,φ(n)=n-1,所以式子变成:

两边同时除a得:

所以得:

用快速幂求一下,复杂度O ( l o g n ) O(logn)O(logn)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n, p;
ll qpow(ll a, ll b, ll mod)
{
  ll ans = 1;
  while (b)
  {
    if (b & 1) ans = (ans * a) % mod;
    a = (a * a) % mod;
    b >>= 1;
  }
  return ans % mod;
}
int main()
{
  scanf("%d%d", &n, &p);
  for (int i = 1; i <= n; i++)
  {
    cout << qpow(i, p - 2, p) << "\n";
  }
  return 0;
}

4.线性递推逆元(神奇小饼干法)

只适用于模数为质数的情况

当p为质数时有:

证明:

并且inverse[0]=0,inverse[1]=1,递归或循环从2开始

写成算法就是一个递归,到1为止,因为1的逆元就是1。

int inv(int t, int p) {
    return t == 1 ? 1 : (p - p / t) * inv(p % t, p) % p;
}

这个方法复杂度是O(n),但并不是说比前两个差,它可以在O(n)的复杂度内算出n个数的逆元,上面的算法加一个记忆性搜索就行了。

int inv(int t, int p) {
    return INV[t] = t == 1 ? 1 : (p - p / t) * inv(p % t, p) % p;
}
#include <bits/stdc++.h>
using namespace std;
const int N = 3e6 + 19;
typedef long long ll;
ll n, p;
ll ans[N];
int main()
{
  scanf("%d%d", &n, &p);
  ans[1] = 1;
  for (int i = 2; i <= n; i++)
  {
    ans[i] = (p - p / i) * ans[p % i] % p;
  }
  for (int i = 1; i <= n; i++)
  {
    cout << ans[i] << "\n";
  }
  return 0;
}

5.阶乘逆元法

只适用于模数为质数的情况

#include<cstdio>
#define ll long long
using namespace std;
ll mul(ll a,ll b,ll mod) //快速幂模板
{
  ll ans=1;
  while(b)
    {
      if(b&1) ans=ans*a%mod;
      a=(a*a)%mod;
      b>>=1;
    }
  return ans%mod;
}
ll n,p;
ll c[5000010]={1};
ll f[5000010];
int main()
{
  scanf("%lld%lld",&n,&p);
  for(int i=1;i<=n;i++)
    c[i]=(c[i-1]*i)%p;
  f[n]=mul(c[n],p-2,p); //获得inv(n!)
  for(int i=n-1;i>=1;i--) //递推阶乘的逆元
    f[i]=(f[i+1]*(i+1))%p;
  for(int j=1;j<=n;j++) //转化并输出
    printf("%lld\n",(f[j]*c[j-1])%p);
}
目录
相关文章
|
Web App开发 资源调度 JavaScript
竟然可以在一个项目中混用 Vue 和 React?
竟然可以在一个项目中混用 Vue 和 React?
1306 0
|
机器学习/深度学习 数据采集 算法
机器学习实战:基于sklearn的工业蒸汽量预测
机器学习实战:基于sklearn的工业蒸汽量预测
570 0
|
安全 Java 数据安全/隐私保护
java JDWP调试接口任意命令执行漏洞
java JDWP调试接口任意命令执行漏洞
888 1
|
机器学习/深度学习 算法 数据挖掘
NumPy有哪些应用场景
【10月更文挑战第22天】NumPy有哪些应用场景
761 2
|
SQL 安全 数据挖掘
牛客网刷题之SQL篇:非技术快速入门39T
这篇文章是关于牛客网上的SQL刷题教程,涵盖了基础的SQL运算符和多个实际的数据分析场景,旨在帮助非技术人员快速入门SQL。
679 0
牛客网刷题之SQL篇:非技术快速入门39T
|
分布式计算 Apache 调度
Apache Hudi 异步Compaction部署方式汇总
Apache Hudi 异步Compaction部署方式汇总
311 0
|
算法 Java
Java数据结构与算法:图算法之深度优先搜索(DFS)
Java数据结构与算法:图算法之深度优先搜索(DFS)
|
机器学习/深度学习 算法 数据可视化
分类算法入门:以鸢尾花数据集为例(下)
分类算法入门:以鸢尾花数据集为例(下)
1253 2
|
人工智能 算法 Java
深度优先搜索(Depth-First Search,DFS)是一种用于遍历或搜索树或图的算法。
深度优先搜索(Depth-First Search,DFS)是一种用于遍历或搜索树或图的算法。

热门文章

最新文章