1.1表示
1.a% b==0表示为b|a(b整除a)
2.a≡b (modm)表示为a% m==b% m
1.2定理
1.欧拉定理:
内容:
解决:
模板:
对于gcd(a,n)=1(互质的正整数a和n),则a^φ(n) ≡1(mod n),即aφ(n)%n==1
2.费马小定理:
p为质数,若gcd(a,b)=1(互质),则a^(p-1) ≡ 1 (mod p),即ap-1%p==1
内容:
解决:
模板:
3.威尔逊定理:
当且仅当p为素数时,(p-1)! ≡ -1 (mod p)
内容:
解决:
模板:
4.卢卡斯定理:
用于计算组合数取模,其中p必须是素数
内容:
解决:
模板:
- 欧几里得定理
- 内容:
gcd(a,b)=gcd(b,a%b)
2.解决:求两数a,b的最大公因数,又称辗转相除法,C++内置函数中的__gcd()函数使用此方法求得
3.模板:
int gcd(int a,int b) {
return a%b ? gcd(b,a%b) : b;
}
7.裴蜀(贝祖)定理
内容:如果a、b是整数,那么一定存在整数x、y使得ax+by=gcd(a,b)。换句话说,如果ax+by=m有解,那么m一定是gcd(a,b)的若干倍。
解决:
模板:
- 扩展欧几里得算法
内容:ax+by=gcd(a,b)=d,在已知a,b的情况下
求解出一组x,y
解决:
1.如果ax+by=1有解,那么gcd(a,b)=1
2.ax+by=gcd(a,b)=d的x,y解
(1)求形如ax+by=c的通解,或从中选取某些特解
(2)求乘法逆元
(3)求解线性同余方程
模板:
int Kgcd(int a,int b,int &x,int &y){
if(b==0){
x=1,y=0;
return a;
}
int r=Kgcd(b,a%b,x,y);
int t=y;
y=x-(a/b)*y,x=t;
return r;
}
8.最大公因数与最小公倍数模板
lcm(a,b)*gcd(a,b)==a*b
lcm(a,b)=(a*b)/gcd(a,b)
int gcd(int a,int b){ //最大公约数
if(b==0) return a;
else return gcd(b,a%b);
}
int lcm(int a,int b){//最小公倍数
return a/gcd(a,b)*b;
}
2.模与余
2.1模运算
1.取模运算:a%p(a mod p),表示a除以p的余数。
2.(a + b ) % p = ( a % p + b % p ) % p
3.(a−b ) % p = ( a % p−b % p + p ) % p (加p防止结果变为负数)
4.(a*b)%p=(a%p)*(b%p)%p
5.除法不满足分配律,需要用到乘法逆元将除法转化为乘法:
6.幂模p:(a^b) % p = ((a % p)^b) % p
7.模运算满足结合律、交换律和分配律。
8.a≡b (modm) 表示a和b模n同余,即a%m==b%m。
2.2同余的性质
1.反身性:a≡a (mod m);
2.对称性:若a≡b(mod m),则b≡a (mod m);
3.传递性:若a≡b(mod m),b≡c(mod m),则a≡c(mod m);
4.同余式相加:若a≡b(mod m),c≡d(mod m),则a c≡b d(mod m);
5.同余式相乘:若a≡b(mod m),c≡d(mod m),则ac≡bd(mod m)。
逆元:
一个数和它的逆元运算后得到的是这个运算的单位元
比如加法的单位元是0(任何数加0都等于其本身)
一个数a的加法逆元就是-a
比如说乘法的单位元是1(任何数乘1都等于其本身)
一个数a的”乘法逆元“就是1/a,即其倒数
2.3快速幂(取模),快速乘法
ll fastpow(ll a,int n){//a的n次方
ll ans=1;
while(n){
if(n&1) ans*=a;
a*=a;
n>>=1;
}
return ans;
}
快速乘法
ll quickmul(ll a,ll b){
ll ret=0;
while(b){
if(b%2) ret=ret+a;
a=a+a;
b/=2;
}
return ret;
}
LL pow(LL a, LL n, LL p){
//快速幂 a^n % p
LL ans = 1;
while(n){
if(n & 1) ans = ans * a % p; //若不取模就去掉p
a = a * a % p;
n >>= 1;
}
return ans;
}
3.数论重要定理及应用
3.1线性同余方程(模线性方程)
3.1定义:
形如:ax≡b (mod n)的方程。
3.2性质
定理1:此方程对于未知量x有解当且仅当 gcd(a,n) | b
定理2:d=gcd(a,n),若d|b,则方程恰好有d个模n不同余的解,否则方程无解
定理3:若x0是方程的任一解,则该方程对模n有d个不同的解,分别为xi=x0+k*(b/d),(k=1,2,…,d-1)
模板:
void RemainderEquation(int a,int b,int n)
{
int X,Y,d;
long long res;
long long min_res;
d=gcd(a,n);
exgcd(a,n,X,Y);
if(b%d == 0)
{
X = X * (b / d) % n;//得到同于方程一解
for(int i = 0 ; i < d; i++)
{
res = (X + (i * (b/d))) % n;
printf("%lld\n",res); //输出所以解
}
min_res=(X%(n/d)+(n/d))%(n/d);
cout<<min_res<<endl; //输出最小解
}else
{
printf("No Sulutions!\n");
}
}
3.2中国剩余定理(模线性方程组)
3.3逆元
定义:若a*x≡1 (mod n)【a*x %n==1】那么x是a在mod n意义下的逆元(a,n是互质的才有逆元)
求法:
- 费马小定理
快速幂即可,ap-2是a的逆元
- 扩展欧几里得算法
3.4唯一分解定理
4素数及其相关定理
4.1质(素)数
1.定义:一个正整数只有除1外和自身之外的任何自然数整除,则这个数称为质数(素数),负责称为合数
2.判定:遍历2-sqrt(n)之间存不存在i满足n%i==0
3.筛选:1-n中所有的质数
AS:对于一个数x,则2x,3x...一定不是素数(素数的倍数(除了本身)都是合数),时间复杂度为O(nloglogn)
做法:遍历2-n中的数为i,将i的倍数标记为合数,会重复。
如果扫描到y未被标记,则为素数。
void AS(int n){
for(int i=2;i<=n;i++){
if(s[i]) continue;
p[tt++]=i;//存储1-n中的素数
for(int j=i*2;j<=n;j+=i) s[j]=1;//合数标记为1
}
}
OL:时间复杂度为O(n)
做法:遍历2-n中的数为i,找到这个数的最小质因子对其进行标记,
bool s[N];//判断一个数是否为素数
void OL(int n){
for(int i=2;i<=n;i++){
if(!s[i]) p[tt++]=i;//存储1-n中的素数
for(int j=0;p[j]*i<=n;j++){
s[p[j]*i]=1;//合数标记为1
if(i%p[j]==0)break;
}
}
}
4.分解质因子
任何一个大于1的正整数都可以被分解为质因子的幂次的积
即N = P1a1*P2a2P3a3P4a4... 如果还想知道质因子的幂次,再用一个数组存储
void zyz(int n){
cnt=0;
for(int i=2;i*i<=n;i++){
if(n%i==0){
f[cnt++]=i;//存储质因子
while(n%i==0) n/=i;
}
}
if(n>1) f[cnt++]=n; //质数在根号N内没有因子,故可能没除完
}
5.互质
定义:gcd(a,b)==1不含共同因子
求gcd的方法为欧几里得算法,时间复杂度O(log(N))
欧拉函数:i指i<=n,且与n互质的数(φ(1)=1)
特殊:
1)φ(p)=p−1 (p为质数)
2)φ(pk)=pk-pk-1 [1,pk]中,和pk 有共同因子(不互质)的数有p*1 , p*2 ... p* pk−1 ,
共计pk-1个
3)若gcd(s,r) = 1则φ(s*r)=φ(s)*φ(r)
4.2反素数
1.1定义
对于任何正整数x,其约数的个数记作g(x)。例如g(1)=1、g(6)=4。
如果某个正整数x满足:g(x)>g(i) 0 < i < x,则称x为反质数。例如,整数1,2,4,6等都是反质数。
即是区间中约数最多的那个数
1.2性质:
1.一个反素数的质因子必然是从2开始连续的质数
2.N=p1^a1 *p2^a2 *…*pn^an,必然有a1>=a2>=a3…>=an
1.3常见用法:
- 给定一个数N,求一个最小的正整数X,使得X的约数个数为N
(2)求出1~N中约数个数最多且数值最小的这个数
(3)求[begin,end]中最小的反素数: