同余定理+逆元

同余定理 定义:

给定一个正整数m,如果两个整数a和b满足(a-b)能够被m整除,即
(a-b)/m得到一个整数,那么就称整数a与b对模m同余,记作a≡b(mod m)
。举个例子:如果两个数a和b之差能被m整除,那么我们就说a和b对模数m同
余(关于m同余)。比如,100-60除以8正好除尽,我们就说100和60对于
模数8同余。它的另一层含义就是说,100和60除以8的余数相同。a和b对m
同余,我们记作a≡b(mod m)。
数学表述:
(a+b)%c=(a%c+b%c)%c
(a*c)%c=(a%c*b%c)%c
性质证明(加法)
a = k1*m+r1
b = k2*m+r2
(a+b)%m=(( k1*m+r1 )+( k2*m+r2 ))%m
= (( k1+k2 )*m+( r1+r2 ))% m
= (r1+r2 )%m
= (a%m+b%m)% m
(a+b)%m = (a%m+b%m)%m

大数取模

一个大数对一个数取余,可以把大数看成各位数的权值与个
位数乘积的和。
比如1234 = ((1 * 10 + 2) * 10 + 3) * 10 + 4,对这个数进
行取余运算就是上面基本加和乘的应用。

int len = a. length ();
int ans = 0;
for (int i = 0; i < len; i ++){
ans = (ans * 10 + a[i] - '0') mod b;
}

逆元

设c是b的逆元,则有b*c≡1(mod m);
推论:(a/b)mod m = (a/b)*1mod m = (a/b)*b*c mod
m=a*c(mod m); 即a/b的模等于a*b的逆元的模;

费马小定理求解逆元
费马小定理:a是不能被质数p整除的正整数,则有a^(p-1) ≡ 1
(mod p)
推导:a^(p-1) ≡ 1 (mod p) = a^(p-2) ≡ 1 (mod p) = a的逆元
为a^(p-2)
代码实现,复杂度Olog(n)

long long quickpow ( long long a, long long b) {
if (b < 0) return 0;
long long ret = 1;
a%= mod;
while (b) {
if (b & 1) ret = (ret * a) % mod ;
b >>= 1;
a = (a * a) % mod;
}
return ret ;
}
long long inv ( long long a) {
return quickpow (a, mod - 2);
}

扩展欧几里得

算法作用:求解a,b 最大公约数m 和a*x+b*y=m 的一个解
实现方法:辗转相除法;
采用递归思想,当b=0时停止递归,此时x=1,y=0;回溯后会
得到一组关于二元一次方程的解

考虑两个方程
:a*x1+b*y1=gcd(a,b),b*x2 +(a%b)* y2=gcd(b,a%b)
\ 由辗转相除法可得到gcd(a,b)= gcd(b,a%b)
\ 从而得到a*x1+b*y1=b*x2 +(a%b)* y2
\ 即a*x1+b*y1=b*x2 +(a -(a/b)*b)* y2
\ =a*y2+b*(x2 -(a/b)* y2)
\ 所以x1=y2 ,y1=x2 -(a/b)* y2.

扩展欧几里得求解逆元
a*x≡1(mod m) 等价于a*x+m*y=1 可以用扩展欧几里得求
得一组解,(x+m)mod m即为a的逆元

int exgcd (int a, int b, int &x, int &y)
{
    if(b == 0)
    {//推理,终止条件1
        x = 1;
        y = 0;
        return a;
    }
    int r = exgcd (b, a%b, x, y);
    int t = y;
    y = x - (a/b) * y;
    x = t;
    return r; //最大公约数
}

递推求解逆元
求1 到n逆元表
这个比较适合逆元比较多的时候。比如数据范围在10e5内,
随机的10e5内的个数的逆元,所以是所有逆元都得求反而会
快点。
代码实现,复杂度O(n)

LL inv[ maxn ];
void Prepare_inv (int n,int M)
{
    inv [1]=1;
    for (int i=2;i <=n;i ++)
    {
        inv [i]=( long long )(M-M/i)* inv[M%i]%M;
    }
}

一般方式求逆元

ll exgcd(ll a,ll b,ll &x,ll &y)
{
	if (b==0)
	{
		x = 1;
		y = 0;
		return a;
	}
	ll r = exgcd (b,a%b,y,x);
	y -= a / b * x;
	
	return r; //最大公约数
}
ll inv(ll a,ll n) //求逆元 
{
    ll x, y;
    ll g = exgcd(a, n, x, y);
    if (g==1)
    	return ((x % n) + n) % n;
    else
    	return -1;//不存在逆元
}

猜你喜欢

转载自blog.csdn.net/qq_40912854/article/details/81187708