zoukankan      html  css  js  c++  java
  • 同余学习笔记

    同余学习笔记

    定义

    ​ 若整数 (a) 和整数 (b) 除以正整数 (m) 的余数相等,则称 (a,b)(m) 同余,记为 (aequiv b (mod m))

    同余系与剩余系

    ​ 对于 (forall ain[0,m-1]) ,集合 {(a+km)} ((kinN)) 的所有数模 (m) 同余,余数都是 (a) 。该集合称为一个模 (m)同余类,简记为 (ar{a})

    ​ 模 (m) 的同余类一共有 (m) 个,分别为 (ar{0},ar{1},cdots,overline{m-1}) 。它们构成 (m)完全剩余系

    (1sim m) 中与 (m) 互质的数代表的同余类共有 (varphi(m)) 个,它们构成 (m)简化剩余系

    ​ 简化剩余系关于模 (m) 乘法封闭。这是因为若 (a,b(1leq a,bleq m))(m) 互质,则 (a*b) 也不可能与 (m) 有相同的质因子,即 (gcd(a*b,m)=1) 。再由余数的定义可知 (a*b mod m) 也与 (m) 互质,即 (a*b mod m) 也属于 (m) 的简化剩余系。

    欧拉定理

    费马小定理

    ​ 若 (p) 是质数,则对于任意整数 (a) ,有 (a^pequiv a (mod p))

    欧拉定理

    ​ 若正整数 (a,n) 互质,则 (a^{varphi(n)}equiv 1 (mod n))

    证明:

    ​ 设 (n) 的简化剩余系为 {(overline{a_1},overline{a_2},cdots,overline{a_{varphi(n)}})}。对 (forall a_i,a_j) ,若 (a*a_iequiv a*a_j (mod n)) ,则 (a*(a_i-a_j)equiv 0) 。因为 (a,n) 互质,所以 (a_i-a_jequiv 0) ,即 (a_iequiv a_j) 。故当 (a_i ot= a_j) 时, (aa_i,aa_j) 也代表不同的同余类。

    ​ 又因为简化同余系关于模 (n) 乘法封闭,故 (overline{aa_i}) 也在简化剩余系中。因此,集合 {(overline{a_1},overline{a_2},cdots,overline{a_{varphi(n)}})}与集合 {(overline{aa_1},overline{aa_2},cdots,overline{aa_{varphi(n)}})}都能表示 (n) 的简化剩余系。综上所述: (a^{varphi(n)}a_1a_2cdots a_{varphi(n)}equiv(aa_1)(aa_2)cdots(aa_{varphi(n)})equiv a_1a_2cdots a_{varphi(n)} (mod n))

    ​ 因此 (a^{varphi(n)}equiv1 (mod n))

    ​ 当 (p) 是质数时, (varphi(n)=n-1) ,并且只有 (p) 的倍数与 (p) 不互质。所以,只要 (a) 不是 (p) 的倍数,就有 (a^{p-1}equiv1 (mod p)) ,两边同乘 (a) 就是费马小定理。另外,若 (a)(p) 的倍数,费马小定理显然成立。

    ​ 证毕。

    欧拉定理的推论

    ​ 若正整数 (a,n) 互质,则对于任意正整数 (b) ,有 (a^bequiv a^{b (mod varphi(n))} (mod n))

    ​ 对于一些计数类题目,如果要计算乘方算式,根据欧拉定理,可以先把底数对 (p) 取模、指数对 (varphi(n)) 取模。再计算乘方。

    ​ 特别的,(a,n) 不一定互质且 (b>varphi(n)) 时,有 (a^bequiv a^{b mod varphi(n)+varphi(n)} (mod n)) 。这意味着即使底数和模数不互质,我们也有办法把指数的规模缩小到容易计算的范围内。上式可以通过寻找 (a^b mod n)指数循环节证明。

    例题

    题面

    题面

    Solution

    (x)(8) 连在一起组成的正整数可以写成 (8*(10^x-1)/9) 。题目要求一个最小的 (x) 满足 (L|8*(10^x-1)/9)

    (gcd(8,L)=d) ,则 (frac{L}{d}|frac{8}{d}(10^x-1)/9) 。由于 (frac{L}{8})(frac{8}{d}) 互质,所以 (frac{L}{d}|(10^x-1)/9) 。整理得到 (frac{9L}{d}|10^x-1) 。写成同余的形式 (10^xequiv 1 (mod frac{9L}{d}))

    写到这里我们想到欧拉定理的形式。

    • 对于 (gcd(10,frac{9L}{d})!=1) ,方程无解。

    证明:以上方程等价于 (10^x=m*frac{9L}{d}+1) ,所以 (gcd(10^x,frac{9l}{d})=gcd(m*frac{9l}{d}+1,frac{9l}{d})=gcd(1,frac{9l}{d})=1)

    • (a,n) 互质,则满足 (a^xequiv 1 (mod n)) 的最小正整数解 (x_0) 一定是 (varphi(n)) 的约数。

    证明:假设 (x_0 ot| varphi(n)) ,则 (varphi(n)=m*x_0+r (0<r<x_0)) 。因为 (a^{varphi(n)}equiv 1 (mod n)) ,那么 (a^{m*x_0+r}equiv 1 (mod n)) 。因为 (a^{x_0}equiv 1 (mod n)) ,那么对上式化简得 (a^requiv 1 (mod n)) 。这与 (x_0) 最小矛盾,假设不成立。原命题成立。

    因此我们只需要求出 (varphi(frac{9l}{d})) ,然后枚举它的约数,用快速幂判断即可。

    时间复杂度: (o(sqrt{L} log L))

    Code

    #include<set>
    #include<map>
    #include<cmath>
    #include<queue>
    #include<cstring>
    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #define del(a,i) memset(a,i,sizeof(a))
    #define ll long long
    #define inl inline
    #define il inl void
    #define it inl int
    #define ill inl ll
    #define re register
    #define ri re int
    #define rl re ll
    #define mid ((l+r)>>1)
    #define lowbit(x) (x&(-x))
    #define INF 0x3f3f3f3f
    using namespace std;
    template<class T>il read(T &x){
    	int f=1;char k=getchar();x=0;
    	for(;k>'9'||k<'0';k=getchar()) if(k=='-') f=-1;
    	for(;k>='0'&&k<='9';k=getchar()) x=(x<<3)+(x<<1)+k-'0';
    	x*=f;
    }
    template<class T>il print(T x){
    	if(x/10) print(x/10);
    	putchar(x%10+'0');
    }
    ll mul(ll a,ll b,ll mod){long double c=1.;return (a*b-(ll)(c*a*b/mod)*mod)%mod;}
    ill qpow(ll x,ll m,ll mod){
    	ll res=1,bas=x%mod;
    	while(m){
    		if(m&1) res=mul(res,bas,mod);
    		bas=mul(bas,bas,mod),m>>=1;
    	}
    	return res%mod;
    }
    ll n,cnt;
    ill gcd(ll x,ll y){return y==0?x:gcd(y,x%y);}
    ill phi(ll x){
    	rl res=x;
    	for(ri i=2;i*i<=x;++i)
    		if(x%i==0){
    			res=res/i*(i-1);
    			while(x%i==0) x/=i;
    		}
    	if(x>1) res=res/x*(x-1);
    	return res;
    }
    il solve(ll n){
    	rl d=gcd(8,n);
    	rl tmp=9*n/d;
    	if(gcd(tmp,10)!=1) printf("Case %lld: 0
    ",++cnt);
    	else{
    		rl p=phi(tmp);
    		for(ri i=1;i<=sqrt(p);++i)
    			if(p%i==0&&qpow(10,i,tmp)==1){
    				printf("Case %lld: %d
    ",++cnt,i);
    				return ;
    			}
    		for(ri i=sqrt(p);i>1;--i)
    			if(p%i==0&&qpow(10,p/i,tmp)==1){
    				printf("Case %lld: %d
    ",++cnt,p/i);
    				return ;
    			}
    	}
    }
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	while(scanf("%lld",&n)!=EOF){
    		if(!n) return 0;
    		solve(n);
    	}
    	return 0;
    }
    

    拓展欧几里得算法

    Bezout定理

    ​ 对于任意整数 (a,b) ,一定存在一对整数 (x,y) 满足 (ax+by=gcd(a,b))

    证明:

    ​ 在欧几里得算法的最后一步,即 (b=0) 时,显然有一对整数 (x=1,y=0) ,使得 (a*1+0*0=gcd(a,0))

    ​ 若 (b>0) ,则 (gcd(a,b)=gcd(b,a\%b))

    ​ 假设存在一对整数 (x,y) ,满足 (b*x+(a\%b)*y=gcd(b,a\%b))

    ​ 因为 (bx+(a\%b)y=bx+(a-blfloor a/b floor)y=ay+b(x-lfloor a/b floor y)) ,所以令 (x^{'}=y,y^{'}=x-lfloor a/b floor y) ,就得到了 (ax^{'}+by^{'}=gcd(a,b))

    ​ 对欧几里得算法的递归过程应用数学归纳法,可知定理成立。

    Bezout定理是按照欧几里得算法的思路证明的,且上述证明的同时给出了整数 (x,y) 的计算方法。这种计算方法被称作拓展欧几里得算法

    int exgcd(int a,int b,int &x,int &y){
        if(b==0){x=1,y=0;return a;}
        int d=exgcd(b,a%b,x,y);
        int z=x;x=y,y=z-y*(a/b);
        return d;
    }
    

    上述程序求出方程 (ax+by=gcd(a,b)) 的一组特解 (x_0,y_0) ,并返回 (a,b) 的最大公约数 (d)

    对于更一般的方程 (ax+by=c) ,它有解当且仅当 (d|c,d=gcd(a,b)) 。我们可以先求出 (ax+by=d) 的一组特解 (x_0,y_0) ,然后令 (x_0,y_0) 同时乘上 (frac{c}{d}) ,就得到了 (ax+by=c) 的一组特解 (frac{c}{d}x_0,frac{c}{d}y_0)

    事实上,方程 (ax+by=c) 的通解可以表示为: (x=frac{c}{d}x_0+kfrac{b}{d},y=frac{c}{d}y_0+kfrac{a}{d},kinN)

    例题

    题面

    题面

    Solution

    假设要跳 (x) 次才能相遇,则题目等价于求一个最小的 (x) ,使得 (a+nxequiv b+mx (mod L))

    整理式子。

    ((n-m)xequiv b-a (mod L))

    将同余号去掉,得 (x(n-m)+kL=b-a) 。其中 (n-m,L,b-a) 均为已知量,所以可以用 (exgcd) 求解。

    注意到 (n-m) 的符号不确定,所以在做题之前进行一下处理,先将 (n-m) 变为正数,再将 (b-a) 变为正数,最后再转换为二元一次方程求解。(注意要开 (long long)

    Code

    #include<bits/stdc++.h>
    #define del(a,i) memset(a,i,sizeof(a))
    #define ll long long
    #define inl inline
    #define il inl void
    #define it inl int
    #define ill inl ll
    #define re register
    #define ri re int
    #define rl re ll
    #define mid ((l+r)>>1)
    #define lowbit(x) (x&(-x))
    #define INF 0x3f3f3f3f
    using namespace std;
    template<class T>il read(T &x){
    	int f=1;char k=getchar();x=0;
    	for(;k>'9'||k<'0';k=getchar()) if(k=='-') f=-1;
    	for(;k>='0'&&k<='9';k=getchar()) x=(x<<3)+(x<<1)+k-'0';
    	x*=f;
    }
    template<class T>il print(T x){
    	if(x/10) print(x/10);
    	putchar(x%10+'0');
    }
    ll mul(ll a,ll b,ll mod){long double c=1.;return (a*b-(ll)(c*a*b/mod)*mod)%mod;}
    it qpow(int x,int m,int mod){
    	int res=1,bas=x%mod;
    	while(m){
    		if(m&1) res=(res*bas)%mod;
    		bas=(bas*bas)%mod,m>>=1;
    	}
    	return res%mod;
    }
    ll a,b,c,n,m,l,x,y;
    ill gcd(ll x,ll y){return y==0?x:gcd(y,x%y);}
    ill exgcd(ll a,ll b,ll &x,ll &y){
    	if(!b){x=1,y=0;return a;}
    	rl d=exgcd(b,a%b,x,y);
    	rl z=x;x=y,y=z-(a/b)*y;
    	return d;
    }
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	read(a),read(b),read(n),read(m),read(l);
    	c=b-a,a=n-m,b=l;
    	if(a<0) a=-a,c=-c,c=(c%l+l)%l;
    	rl d=gcd(a,b);
    	if(c%d!=0) printf("Impossible");
    	else{
    		exgcd(a,b,x,y);
    		x=1ll*x*c/d;ri mod=b/d;
    		printf("%lld",(x%mod+mod)%mod);
    	}
    	return 0;
    }
    

    乘法逆元

    若整数 (b,m) 互质,并且 (b|a) ,则存在一个整数 (x) ,使得 (a/bequiv a*x (mod m)) 。称(x)(b) 的模 (m) 的乘法逆元。记为 (b^{-1}(mod m))

    因为 (a/bequiv a*b^{-1}equiv a/b*b*b^{-1}(mod m)) ,所以 (b*b^{-1}equiv 1(mod m))

    如果 (m) 为质数(此时用 (p) 代替 (m) ),并且 (b<p) ,根据费马小定理, (b^{p-1}equiv1(mod p)) ,即 (b*b^{p-2}equiv1(mod p)) 。因此,当模数 (p) 为质数时, (b^{p-2}) 即为 (b) 的乘法逆元

    如果只是保证 (b,m) 互质,那么乘法逆元可通过求解同余方程 (b*xequiv 1(mod m))得到

    运用乘法逆元,我们在计数类问题中遇到 (a/b) 这样的除法算式,也可以先把 (a,b) 各自对模数 (p) 取模,再计算 (a*b^{-1}(mod p)) 作为最终结果。当然,前提是必须保证 (b,p) 互质。

    线性同余方程

    给定正数 (a,b,m) ,求一个整数 (x) 满足 (a*xequiv b(mod m)) ,或者给出无解。因为未知数的指数为 (1) ,所以我们称之为一次同余方程,也称为线性同余方程。

    (a*xequiv b(mod m)) 等价于 (a*x-b)(m) 的倍数,不放设为 (-y) 倍。于是该方程可以改写为 (a*x+m*y=b)

    线性同余方程有解当且仅当 (gcd(a,m)|b)

    中国剩余定理

    (m_1,m_2,cdots,m_n) 是两两互质的整数, (m=prodlimits_{i=1}^n m_i)(M_i=m/m_i)(t_i) 是线性同余方程 (M_it_iequiv 1(mod m_i)) 的一个解。对于任意的 (n) 个整数 (a_1,a_2,cdots,a_n) ,方程组 (left{egin{matrix} xequiv a_1(mod m_1)\ xequiv a_2(mod m_2)\ cdots\ xequiv a_2(mod m_3)\ end{matrix} ight.) 有整数解,解为 (x=sumlimits_{i=1}^n a_i M_i t_i)

    证明:

    ​ 因为 (M_i=M/m_i) ,是除 (m_i) 外所有模数的倍数,所以 (forall k ot= i,a_i M_i t_iequiv 0(mod m_k)) 。又因为 (a_iM_it_iequiv a_i(mod m_i)) ,所以带入 (x=sumlimits_{i=1}^n a_i M_i t_i) ,原方程组成立。

  • 相关阅读:
    Windows Install Twisted 安装Twisted
    raspberry pi随图形界面开机启动 被执行两次的问题
    将任意程序(如.bat文件)作为Windows服务运行
    xampp无法打开phpmyadmin解决方案
    python的subprocess无法进行通信(无法通过管道输入数据)的问题解决
    关于接地/共地
    树莓派字体安装
    windows 不能在本地计算机启动apache2 的解决方法(不是修改端口)
    5 November in 614
    模拟退火算法
  • 原文地址:https://www.cnblogs.com/TheShadow/p/11401941.html
Copyright © 2011-2022 走看看