同余概述
定义: 同余给定正整数,若用去除两个整数和,所得的余数相同,称a和b对模同余,记作,并称该式为同余式,否则,称和对模不同余。
定理:
- ,当且仅当
- ,当且仅当存在正整数,使得
- 同余关系是等价关系,即
(1)自反性:
(2)对称性:,则
(3)传递性:,则
定义:由与同余关系是等价关系,对于所有整数会被分为的集合,这些集合称为模剩余类(同余类)。每个集合中的任意两个数都是模同余的。
定义:一个整数集合,且满足对于任意的整数在此集合中存在一个元素与该整数模同余,该整数的集合是模的完全剩余系。
定理:若,,,是整数,是正整数,且,则:
4.
5.
6.
7. ,则
8. ,其中为任意整数,即同余式可以相加
9. ,即同余式可以相乘
10. ,
11. ,其中为任一整数多项式
定理:若a,b,c,d为整数,m为正整数,则:
- 若,且,则
- 若,则,其中为和的最大公约数
- ,同时成立,当且仅当
证明上式1, 若 ,则,令,两边同除,,,即
证明上式2,若为和的公约数,且,所以,对于所有上式都成立,反之亦然成立,即与和与的公约数集相同,所以
一元线性同余方程
定义:是整数,是正整数,形如,且是未知整数的同余式称为一元线性同余方程.
定理:是整数,是正整数,.如果,则方程恰有个模的不同余的解,否则方程无解。
证明:方程有解时,,为整数,即,由裴蜀定理可知,对任何整数和它们的最大公约数,关于未知数和的线性不定方程(称为裴蜀等式):若是整数,且,那么对于任意的整数,都有一定是的倍数,特别地,一定存在整数,使成立。因为y为整数,不是定值,所以把上式化为,随着值变化,存在个不同余的解。所以如果,,那么方程恰有个不同余解 ,个解分别关于同余,分别为
求解一元线性同余方程时可以使用扩展欧几里得算法.
void exgcd(int a,int b,int&d,int&x,int&y)//扩展欧几里得算法
{
if(b==0)
{
x=1,y=0;
d=a;
return;
}
else
{
int r=exgcd(b,a%b,x,y); //r=GCD(a,b)=GCD(b, a%b)
int t=x;
x=y;
y=t-a/b*y ;
return;
}
}
int f(int a,int b,int m)//计算同余方程所有解
{
int x,y,d;
exgcd(a,m,d,x,y);
if(b%d)
return -1;//无解
x=x*(b/d)%m;
for(int i=1;i<=d;i++)
ans[i]=(x+(i-1)*m/d)%m;
}
一元线性同余方程组
任意的一元线性同余方程组都可以化为,而一元线性同余方程组就是多个这样的式子联合求解。
例如: 与,这两个方程就构成了一个同余方程组。
令,此时方程组有解的充分必要条件是,此时方程仅有一个非负整数解。
证明:讲两式写为,联立可得,即,由裴蜀定理可知成立。此时方程的解即为或
上面式子可由扩展欧几里得求解和.
对于多个方程的方程组,这样两两求解合并即可求出最后的解。
int solve()
{
int n,m1,b1,m2,b2,x,y,d,flag=1;
cin>>n>>m1>>b1;
for(int i=1;i<n;i++)
{
cin>>m2>>b2;
int c=b2-b1;
exgcd(m1,m2,d,x,y);
if(c%d!=0)
flag=0;
x=(x*c/d)%(m2/d);//求小于m2/d的解
b1=m1*x+b1;
m1=m1*(m2/d);//合并后m应为m1和m2的最小公倍数
}
if(flag) return b1;
else return -1;
}
中国剩余定理
中国剩余定理是中国古代求解一次同余式组的方法。是数论中一个重要定理。又称中国余数定理。
给定一个同余式组如下:
中国剩余定理说明:假设整数两两互质,则对任意的整数:,方程组有解,并且通解可以用如下方式构造得到:
设(为模意义下的逆元),即
那么方程组的通解
在模M情况下只有一个解
下面证明摘自百度百科:
中国剩余定理求解同余方程组:
int m[maxx];
int intChina(int n)
{
int M=1,Mi,x0,y0,d,ans=0;
for(int i=1;i<=n;i++)
M*=m[i];
for(int i=1;i<=n;i++)
{
Mi=M/m[i];
exgcd(Mi,m[i],d,x0,y0)
ans=(ans+Mi*x0*a[i])%M;
}
return ans;
}
由中国剩余定理可得的两个定理
- 若是正整数,那么有.
- 正整数是互质的,当且仅当a与b是互质的。
中国剩余定理应用:
poj1006.Biorhythms
题目大意:人自出生起就有体力,情感和智力三个生理周期,分别为23,28和33天。一个周期内有一天为峰值,在这一天,人在对应的方面(体力,情感或智力)表现最好。通常这三个周期的峰值不会是同一天。现在给出三个日期,分别对应于体力,情感,智力出现峰值的日期。然后再给出一个起始日期,要求从这一天开始,算出最少再过多少天后三个峰值同时出现。
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxx=1e6+7,M=21252;
void exgcd(int a,int b,int&d,int&x,int&y)
{
if(b==0)
{
x=1,y=0;
d=a;
return;
}
else
{
exgcd(b,a%b,d,x,y);
int t=x;
x=y;
y=t-a/b*y ;
return;
}
}
int m[maxx],a[maxx];
int intChina(int n)
{
int Mi,x0,y0,d,ans=0;
for(int i=1;i<=n;i++)
{
Mi=M/m[i];
exgcd(Mi,m[i],d,x0,y0);
ans=(ans+Mi*x0*a[i])%M;
}
return ans;
}
int main()
{
ios::sync_with_stdio(0);
int p,e,i,d,s=1;
m[1]=23,m[2]=28,m[3]=33;
while(cin>>p>>e>>i>>d&&p!=-1)
{
a[1]=p;
a[2]=e;
a[3]=i;
int ans=intChina(3);
while(ans<=d)
ans+=M;
cout<<"Case "<<s++<<": the next triple peak occurs in "<<ans-d<<" days."<<endl;
}
}
来源:CSDN
作者:Crazy_pine
链接:https://blog.csdn.net/weixin_43956585/article/details/104192344