一、质数(素数)
从2开始,只有1和它本身的数叫做素数
1.质数的判定--试除法 ( O(N^1/2)
for(int i =2 ;i<=n/i ;i++)
2.分解质因数--试除法(O(logN~N^1/2))
void divide(int x)
{
for(int i =2 ;i<= n/i ;i++)
if(x%i==0)
{
int s = n ;
while(x%i==o) x/=i,s++;
cout<<i<<' '<<s<<endl;
}
if(x>1) cout<<x<<' '<<1<<endl;
}
3.筛选质数--埃式筛法
原理:依次枚举i,将i的倍数全部删除,剩下的序列就是素数的序列
int prines[N],cnt; //存素数
bool st[N]; //判断是否需要筛除 true表示筛除
void get_prinmes(int n)
{
for(int i = 2 ;i<=n/i; i++)
{
if(st[i]) continue ;
primes[cnt++] = i;
for(int j = i+ i ; j<=n;j+=i;
st[j[ = true ;
}
}
由于以上算法在进行筛除元素的时候会有重复的操作,于是我们改进了一个算法,解决了该问题。
改进--线性筛算法--O(NN)
算法原理:
从小到大枚举i
如果当前数没被划掉,必然是质数,记录下来
枚举已经被记录的质数(如果该质数与i的合数越界,循环中断)->i*primes【j】
a.合数未越界,则划掉合数,继续循环
b.条件:i%primes【j】==0 可以保证合数只被最小质因子划掉,保证了不会重复,是该算法的核心
1.若i是质数,则循环最多可以枚举到本身
2.若i是合数,则最多可以枚举到自身的最小质数后中断循环
int prines[N],cnt; //存素数
bool st[N]; //判断是否需要筛除 true表示筛除
void get_prinmes(int n)
{
for(int i = 2 ;i<=n/i; i++)
{
if(!st[i]) primes[cnt++] = i;
for(int j=0;primes[j]<=n/i;j++)
{
st[primes[j]*i] = true ;
if(i%primes[j] == 0) break;
}
}
}
二、约数
约数,又称因数。整数a除以整数b(b≠0) 除得的商正好是整数而没有余数
1.求一个数的所有约数--试求法
vector<int>get_divisors(int x)
{
vector<int> res;
for(int i=0;i<=x/i ;i++)
if(x%i==0)
{
res.push_back (i);
if(i!=x/i)res.push_bacf(x/i);
}
sort(res.begin(),res.end());
return res;
}
如果 N= P1^C1 * P2^C2 * ... * Pk^Ck;
2.求约数的个数:(c1=1)*(c2+1)*(c3+1)*...*(cK+1);
基本公式:所有质因数的指数加上1的积
3.求约数的和:(p1^0+p1^1+...+p1^c1)*...*(pk^0+pk^1+...+pk^ck)
基本公式:先把每一个质因数从0次幂加到最高次幂,再相乘
4.求最大公约数--欧几里得算法(辗转相除法)
基本原理:gcd(a,b) = gcd(b,a mod b)
int gcd(int a,int b)
{
if(!b) return a;
return gcd(b,a%b);
}
三、欧拉函数
给定一个n,求得1到n中与n互质的数的个数
基本公式:φ(n)=n * (1-1/P1) * (1-1/P2) * … * (1-1/Pn)
其中,φ(n)表示1~n中与n互质的个数,p表示质因数。
int phi(int n)
{
int ans = n;
for(int i = 2;i * i <= n;i++)//分解质因子
{
if(n % i == 0)
{
ans = ans / i * (i-1);
//现在的i为质因子,根据公式(1-(1/i)),也就是乘以(i-1)/i 处理一下
while(n % i == 0)
n /= i;
}
}
if(n > 1)
ans = ans / n * (n-1);
return ans;
}
四、快速幂算法--O(logK)
快速的求出a^k(mod)p的结果 速度快
基本原理:反复平方
例子:求3^10
1. 3^10 ----> 9^5
2. 9^5 ----> 9*9^4
3. 9*9^4 ----> 9*81^2
4. 9*81^2 ----> 6561*9
以上过程中会不断取模
long long qmi(long long m, long long k,long long p) //求m^k(mod)p
{
long long res = 1% p,
t = m;
while(K)
{
if(k&1) res =res * t % p;
t = t * t % p;
k>>=1;
}
return res;
}
五、扩展欧几里得算法
【裴蜀定理】
对于任意一对正整数a,b。一定存在两个参数x,y。使得: ax + by = (a,b)最大公约数。
[例题] 给一个同余线性方程 aX = b(mod m)请你求出一个X满足该式
稍微处理以下 得到 ax + my = b 从定义出发,b必须是(a,m)的倍数方程有解
求解上述线性方程:
当b==0时,明显 X=1,Y=0是方程的一组特解
当b不等于0时,gcd(a,b) = gcd(b,a%b);代入方程
-->by + (a %b) x = d;
-->by + (a- (a/b)*b )x = d;
-->ax + b(y- (a/b) x)= d;
可以看出,经过一次变换后
x= y1 ;
y = x1 - (a/b) *y1 ;
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int exgcd(int a,int b,int x,int y)
{
if(!b)
{
x=1,y=0;return a;
}
int d = exgcd(b,a&b,y,x);
y-=a/b*x;
return d;
}
int main()
{