zoukankan      html  css  js  c++  java
  • 关于逆元的概念、用途和可行性的思考(附51nod 1013 和 51nod 1256)

    【逆元的概念】

     

    逆元单位元这个概念在群中的解释是:  逆元是指数学领域群G中任意一个元素a,都在G中有唯一的逆元a',具有性质a×a'=a'×a=e,其中e为该群的单位元。

     

    的概念是:  如果独异点(幺半群)中每一个元素都有逆元,那么这个独异点(幺半群)叫做群。

     

    独异点幺半群):  有单位元的半群。

     

    半群:  可结合的代数系统。即 ,有 

     

    代数系统:我的理解是代数系统包含一个数的集合A和至少一个运算规则,所有的运算都是封闭的,不会产生不在A集合中的数。

    我们知道的实数集合R和加减乘除等一系列运算规则就组成了一个代数系统。根据上面的概念我们当然知道这是一个群。

     

    简单来说:对于任意群中元素a,b,如果a*b = 1 ,那么a就是b的左逆元,b就是a的右逆元。(如果这个群满足交换律,这个群就是交换群,那么a和b互为逆元。

     

     

    这里有一个例题,就是求逆元的:

    当然这是一道单纯求逆元的题。

       (K*M)% N = 1

    看到这个我们想把%消掉,看起来就会简单了。

    ==>   (K*M-1)%N = 0

    ==>   K*M-1 = S*N (S为未知数)

    现在我们成功的消掉了%,这个等式只有K和S两个未知数。

    如果还没看出来的话,我们把K换成x,S换成y,再移项看看:

    ==>    M*x - N*y = 1

    是不是很熟悉,对,就是拓展欧几里得。

    ll gcd(ll a,ll b,ll &x,ll &y){
        if (b==0){
            x=1,y=0;
            return a;
        }
        ll q=gcd(b,a%b,y,x);
        y-=a/b*x;
        return q;
    }

    这样能够解出x,y的一对解,再把它移到适合的范围内就得到了我们的结果。

    这题的代码如下:

    #include <iostream>
    #include <algorithm>
    #include <string>
    #include <stdio.h>
    #include <string.h>
    #include <math.h>
    #define rep(u,i,n) for(int u = i;u <= n; u++)
    typedef long long ll;
    using namespace std;
    ll gcd(ll a,ll b,ll &x,ll &y){
        if (b==0){
            x=1,y=0;
            return a;
        }
        ll q=gcd(b,a%b,y,x);
        y-=a/b*x;
        return q;
    }
    int main() {
      ll n,m,x = 0,y = 0;
      while(cin >> m >> n){
        gcd(n,m,x,y);
        if(y > 0) cout << y << endl;
        else cout << n+y << endl;
      }
      return 0;
    }

     

     

     

    【逆元的用途】 除法取模

    我们知道 (a*b)%n = c --> ((a%n)*(b%n))%n = c;

    但是(a/b)%n 该怎么求呢?

    如果n = 11, a = 3, b = 10 的话,直接算会导致结果错误(3/10)%11 = 0。

    我们知道3/10是有值的,但是直接算结果会变成0,肯定出了某种错误。

    这个错误我们暂时不做讨论,着重解决问题。

     

    这时乘法逆元就派上用场了我们知道(3/10)%11 ==> (3*(1/10))%11

    而1/10在乘法上是10的逆元(mod n = 11),意思就是我们用10的逆元取代1/10的位置就可以解决了。

    (3/(10的逆元))%11就是我们要的结果。

     

    于是我们成功的解决了除法时取模的问题。

     

    这里有一个例题:

     

    这个逆元是手动求的,懒得写求逆元代码。

     

    代码如下:

    #include <bitsstdc++.h>
    typedef long long ll;
    using namespace std;
    const int mod = 1000000007;   
    ll mod_pow(ll x,ll n)  
    {  
      ll ans = 1;  
      while(n > 0) {  
        if(n % 2 == 1){
            ans = ans * x % mod;
            } 
            n /= 2;
            x = x*x % mod;
      }  
      return ans;  
    }   
    int main()  
    {     
      ll n,ans;  
      cin >> n;  
      n++; 
      ans = (mod_pow(3,n)-1)*500000004%mod; // 500000004是2对mod的逆元 ,逆元在除以后取模时使用 
      cout << ans << endl;  
      return 0;  
    }  

     

  • 相关阅读:
    Linux负载均衡--LVS(IPVS)主要算法实现分析
    使用alarm控制阻塞connect()超时的示例
    使用select控制非阻塞connect()超时的示例
    再出发
    nulls_hlist原理 和 tcp连接查找
    linux支持大容量硬盘
    Nmap扫描原理(下)
    linux常用命令
    Linux下面自动清理超过指定大小的文件
    Memcached介绍
  • 原文地址:https://www.cnblogs.com/zhangjiuding/p/7546158.html
Copyright © 2011-2022 走看看