zoukankan      html  css  js  c++  java
  • 洛谷 P3811 【模板】乘法逆元(欧拉定理&&线性求逆元)

    题目传送门

    逆元定义

    逆元和我们平时所说的倒数是有一定的区别的,我们平时所说的倒数是指:a*(1/a) = 1,那么逆元和倒数之间的区别就是:假设x是a的逆元,那么 a * x = 1(mod p),也就是只多了一个取余的操作,这个取余的操作,就会保证a的逆元不一定只是a的倒数。那么我们的逆元有什么作用呢?

    并且取余还不满足下面式子:( a/b )%p = (a%p  /  b%p)  %  p ,那么我们如果遇到b过大必须在中间过程进行取余的操作,那么我们会发现在乘法中满足:(a*b) % p = (a%p  *  b%p) %p,那么我们只要将上面式子转换为下面乘法的式子就可以了

    我们用inv(b)来表示b的逆元,那么他一定满足:b*inv(b) = 1(mod p)    ==>  b = 1/inv(b) ,那么我们代入上面的除法的式子:(a/b)%p =     (a * inv(b)) %p = (a%p  *  inv(b)%p) % p

    这样我们就可以根据逆元来将除法取余的式子转换为乘法取余的式子
    原文:https://blog.csdn.net/li1615882553/article/details/80001473

    一:欧拉定理求逆元

     1 #include<iostream>
     2 #include<cstdio>
     3 
     4 using namespace std;
     5 
     6 long long m,k,n,sum,s;
     7 
     8 inline long long phi(long long x) {
     9     long long res = x,a = x;
    10     for(int i = 2;i * i <= a; i++)
    11         if(a % i == 0) {
    12             res = res / i * (i - 1);
    13             while(a % i == 0)
    14                 a = a / i;
    15         }
    16     if(a > 1)
    17         res = res / a * (a - 1);
    18     return res;
    19 }
    20 
    21 inline void _out(long long pp,long long v) {
    22     sum = 1;
    23     while(pp > 0) {
    24         if(pp % 2 != 0)
    25             sum = (sum * v) % m;
    26         pp = pp / 2;
    27         v = (v * v) % m;
    28     }
    29     printf("%d
    ",sum);
    30 }
    31 
    32 int main() {
    33     scanf("%d%d",&n,&m);
    34     k = phi(m);
    35     s = k - 1;
    36     for(int i = 1;i <= n; i++)
    37         _out(s,i);
    38     return 0; 
    39 }
    欧拉定理

    但因为欧拉定理求逆元时间复杂度为O(nlongn),所以本题会被卡两个点。

    二:线性求逆元

     1 #include<iostream>
     2 #include<cstdio>
     3 
     4 using namespace std;
     5 
     6 int n,inv[3000001];
     7 long long p;
     8 
     9 int main() {
    10     inv[1] = 1;
    11     scanf("%d%lld",&n,&p);
    12     for(int i = 2;i <= n; i++) 
    13         inv[i] = (p - p / i) * inv[p % i] % p;
    14     for(int i = 1;i <= n; i++)
    15         printf("%d
    ",inv[i]);
    16     return 0;
    17 }
    线性

    因为是线性,O(n)足够优秀,所以轻松过掉本题

  • 相关阅读:
    Django学习笔记第六篇--实战练习二--简易实现登录注册功能demo
    追踪溯源--抓住隐藏在NAT后面的罪犯
    Linux内核态、用户态简介与IntelCPU特权级别--Ring0-3
    Windows2008 IIS配置FTP站点
    .NET RSA解密、签名、验签
    Quartz.NET 入门
    使用Topshelf创建Windows服务
    xcode6 新建项目真机调试无法全屏
    .NET 二维码生成(ThoughtWorks.QRCode)
    iOS手机应用开发原型模板及开发流程
  • 原文地址:https://www.cnblogs.com/lipeiyi520/p/11267186.html
Copyright © 2011-2022 走看看