同余

同余
给定一个正整数m,如果两个整数a和b满足a-b能够被m整除m|(a-b),那么整数a与b对模m同余,记为a≡b (mod m)
举例a=100,b=60,a-b=40,m=8,8|40,故100≡60 (mod 40)。
同余另一种说法是a%m==b%m。
主要性质
如果a≡b (mod m),c为整数则
a+c≡b+c (mod m)
a-c≡b-c (mod m)
a*c≡b*c(mod m)
(a+b) mod m=((a mod m)+(b mod m)) mod m
(a-b) mod m=((a mod m)-(b mod m)) mod m
(a*b) mod m=((a mod m)*(b mod m)) mod m
对于减法(a-b)%m=(a-b+m)%m
逆元
(1)定义:
 就是一个数的倒数,那为什么要求一个数的倒数:比如a/b这个时候b的值特别大,就是导致double精度不够所以我们要将a/b换成a*c,其中 。
设c是b关于模m的逆元,则有b*c ≡1(mod m);
推论:(a/b)mod m=(a/b)*1 mod m=(a/b)*b*c mod m=a*c mod m;即a/b的模等于a*(b的逆元)。
逆元的求法
费马小引理求解逆元
费马小引理:如果a是不能被质数p整除的正整数则有ap-1 ≡1(mod m)。
推导:a与ap-2互为逆元。

#include<iostream>
using namespace std;
long long quickpow(long long a,long long b,long long mod)
{
	long long ret=1;
	a%=mod;
	while(b)
	{
		if(b & 1 ) ret = ( ret *a ) % mod;
		a = (a * a)% mod;
		b>>=1;
	}
	return ret;
}
//mod必须为素数,且(a,mod)=1 
long long inv(long long a,long long mod)
{
	return quickpow(a,mod-2,mod);
}
int main()
{
	int n,m;
	cin>>n>>m;
	cout<<inv(n,m)<<endl;
	return 0;
}

扩展欧几里得求逆元

算法的作用:求解a,b的最大公约数m和a*x+b*y=m的一个解。
求a*x ≡1 (mod m) 等价求a*x+m*y=1,可以用扩展殴几里得求得一组解,(x+m) %m 就是a的逆元。条件是(a,m)=1。

#include<iostream>
using namespace std;
typedef long long ll;
void extgcd(ll a,ll b,ll& d,ll& x,ll& y)
{
	if(!b)
    {
    	d=a;x=1;y=0;
    }
    else
    {
    	extgcd(b,a%b,d,y,x);
    	y-=x*(a/b);
    }
}
int ModularInverse(int a,int b)
{
	ll d,x,y;
	extgcd(a,b,d,x,y);
	return d==1?(x+b)%b:-1;  //返回的结果就是(1/a)mod(b)的结果
	// complete this part
}
int main()
{
	int x,y;
	cin>>x>>y;
	cout<<x<<"的模"<<y<<"的逆元:"<<ModularInverse(x,y)<<endl;
	cout<<y<<"的模"<<x<<"的逆元:"<<ModularInverse(y,x)<<endl;
	return 0;	
}

线性求逆元

来看带余除法 式子 p=k*i+r 
我们可以写成 k*i+r≡0(mod p) 
式子两边同乘 i-1*r-1 (i-1,r-1皆为模p意义下的逆元) 
所以我们有 k*r-1+i-1≡0(mod p) 
i-1≡-k*r-1(mod p)
i-1≡-(p/i)*(p%i)-1(mod p)
所以i-1可以用(p%i)-1推出,所以就可以用递推式求出来1到i之间所有数的逆元。

#include<iostream>
using namespace std;
const int MAXN=100010;
//1、线性求逆元
int inv[MAXN];
void INV(int a,int p)//线性求到a的逆元
{
    inv[1] = 1;
    for (int i=2; i<=a; ++i)
        inv[i] = (-(p/i))*inv[p%i]%p;
}
//2、单独求某个值的逆元
int INVd(int a,int p)//线性求a的逆元
{
     if (a==1) return 1;
     return ((-(p/a)*INVd(p%a,p))%p);
}
int main()
{
	int a,p;
	cin>>a>>p;
	INV(a,p);
	for (int i=1;i<=a;i++)
	{
		cout<<(inv[i]+p)%p<<" "; 
	} 
	cout<<endl;
	for (int i=1;i<=a;i++)
	{
		cout<<(INVd(i,p)+p)%p<<" ";
	}
	cout<<endl;
	return 0;
}

 

posted @ 2022-03-10 21:00  心悟&&星际  阅读(139)  评论(0编辑  收藏  举报