模运算

2 篇文章 0 订阅
1 篇文章 0 订阅

模运算

(从点点搬运过来)

1. 欧几里德算法——求最大公约数

递归:

// initially a>b>=0, return greatest common divisor

int gcd(int a,int b)   
{
    return b? gcd(b,a%b) : a;
}

非递归:

#include <algorithm>
int gcd(int a,int b)
{
    while(a=a%b)   { swap(a,b); }
    return b;
}

2. 欧几里德扩展算法

定理:对不全为零的两个非负整数 a,b,其最大公约数为 gcd (a,b),则必存在两个整数 x , y ,使得 a*x+b*y=gcd (a,b)

算法简述:利用欧几里德算法的中间过程,不断将a,b值用b,a%b代替,直到a%b为零,则有x=1,y=0。

证明与实现:
1 . 假设a>b,当 b=0 ,则 x=1,y=0.

2 . a*x1 + b*y1 =gcd (a,b)
同理 b*x2 + (a%b)y2 =gcd (b,a%b)=gcd (a,b) 成立,且因为 (a%b)=a-b(a/b)
所以 x1=y2;
y1=x2-(a/b)*y2;
所以x1,y1可以从x2,y2的值推导出来。并且最后a%b必然可以达到零,可以退出递归。

递归:

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int exgcd(int a,int b,int &x,int &y) 
{
    if(!b) return x = 1, y = 0, a;
    int g = exgcd(b,a%b,y,x);
    y-=a/b*x;
    return g;
}

lrj版:

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
using namespace std;

typedef long long ll;
const int maxn = 1000000;

ll ext_euclid(ll a, ll b, ll& d, ll& x,ll& y ) {
    if(!b) { d = a; x = 1; y = 0;}
    else { ext_euclid(b, a%b, d, y ,x); y -= x*(a/b);}
}   // d=gcd(a,b);

扩展欧几里德的应用: 1> 求解不定方程。2> 求解同模方程。3> 求乘法逆元
1> a*x+b*y=m,有解的充要条件为m % gcd(a,b)==0
2> a*x = b (mod p)
3> a模b 的乘法逆元 。x*(1/a) mod b=x*(a’) mod b 等同于 a*a’=1(mod b) 当且仅当 gcd(a,b)=1。可转化为,求a*a’+b*b’=1,其中,a’是a模b的乘法逆元,b‘是b模a的乘法逆元。

求乘法的逆元:1>欧几里德 2>快速幂(p为质数) a^(p-2) * a = 1 (mod p)。故a^(p-2)为a的逆。

3. 欧拉函数

在数论中,对正整数n,欧拉函数是小于或等于n的数中与n互质的数的数目。

φ函数的值

通式:φ(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…..(1-1/pn),其中p1, p2……pn为x的所有质因数,x是不为0的整数。φ(1)=1(唯一和1互质的数就是1本身)。
与欧拉定理、费马小定理的关系
对任何两个互质的正整数a, m, m>=2有
a^φ(m)≡1(mod m)
即欧拉定理
当m是质数p时,此式则为:
a^(p-1)≡1(mod m)
即费马小定理。

求phi[2]~phi[n]的值:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

#define maxn 100

int main()
{
    int prime[maxn+1],phi[maxn+1],tot=0,pri[maxn+1];
    int i,j;
    prime[0]=prime[1]=0;
    for(i = 2; i <= maxn; i ++)  prime[i] = 1;
    for(i = 2; i * i <= maxn; i ++)
        if(prime[i]) 
            for(j = i + i; j <= maxn; j += i)   //if i is not so big.you can start from j = i * i
                prime[j]=0;  
       //find all prime numbers
    for(i = 1; i <=maxn; i ++)
        phi[i]=i;
    for(i = 2; i <= maxn; i ++)
        if(prime[i])
            for(j = i; j <= maxn; j += i)
                phi[j] = phi[j] / i *(i - 1); 
        //  /i firstly,or the number will overflow
    for(i = 2; i <= maxn; i++)  cout<<i<<" "<<phi[i]<<endl;
    return 0;
}

中国剩余定理

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
using namespace std;

typedef long long ll;
const int maxn = 1000000;

ll ext_euclid(ll a, ll b, ll& d, ll& x,ll& y ) {
    if(!b) { d = a; x = 1; y = 0;}
    else { ext_euclid(b, a%b, d, y ,x); y -= x*(a/b);}
}  // d=gcd(a,b);

//n , x=a[i](mod m[i]), 0<=i<n
ll china(int n,int *a,int *m)
{
    ll M = 1, d, y, x = 0;
    for( int i = 0; i < n; i++) {
        M *= m[i];
    }
    //printf("M=%lld\n",M);
    for( int i = 0; i < n; i++) {
        ll w = M / m[i];
        ext_euclid(m[i],w,d,d,y);  //d,y.because relatively prime,gcd(w,m)=1 = d = original x;
        cout<<"w = "<<w<<"  y = " << y << endl; 
        x = (x + y*w*a[i]) % M;
    }
    return (x+M) % M;
}

int main() {
    int n,a[maxn+1],m[maxn+1];
    while(scanf("%d",&n),n) {
        for(int i = 0; i < n; i ++) {
            scanf("%d%d",&m[i],&a[i]);
        }
        ;
        cout<<"--> "<<china(n,a,m)<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值