质数与约数

质数与约数:

 

整除与约数

n 为非负整数,d 为正整数,若 nd 为整数,则称 d 整除 n,记为dn。此时,则称 dn 的约数,或因数、因子;称 nd 的倍数。

 

质数与合数的定义:

对于 n2 ,若 1<i<n,in ,则称 n 为质数,否则 n​ 为合数。

 

质数判定:

试除法:

单次时间复杂度 O(n )

代码
bool is_prime(int n) {
	if(n < 2)
		return false;
	for(int i=2; i<= sqrt(n); ++i) {
		if(n % i == 0)
			return false;
	}
	return true;
}

 

质数筛法一:

2n 枚举整数 i,标记大于 i 且不大于 ni 的倍数。枚举到 i 时,若 i 没有被标记过,则 i 为质数。

时间复杂度 O(i=1nni)=O(nlogn)

代码
void found_prime() {
	memset(vis, 0, sizeof(vis));
	vis[0] = 1; vis[1] = 1; // 特殊处理 0 和 1
	for(int i=2; i<=n; ++i) {
		for(int j=i*2; j<=n; j+=i)
			vis[j] = 1; // 标记合数
    }
}

 

埃氏筛:

只需要枚举质数的倍数就可以标记到所有合数了。实际上对于每个质数 p 而言,小于p2p 的倍数在扫描到更小的质数时就已经被标记过了。

2n 枚举整数 i,若 i 是质数,则把 i2 , (i+1)×i, , ni×i 标记为合数。枚举到 i 时,若 i 没有被标记过,则 i 为质数。

时间复杂度 O(pr[i]nnpr[i])=O(nloglogn)

代码
void found_prime() {
	memset(vis, 0, sizeof(vis));
	vis[0] = 1; vis[1] = 1; // 特殊处理 0 和 1
	for(int i=2; i<=n; ++i) {
		if(!vis[i]) { // i 为质数
			for(int j=i*i; j<=n; j+=i)
				vis[j] = 1; // 标记合数
		}
	}
}

 

线性筛:

用每一个合数的最小质因子来标记这个合数。时间复杂度 O(n)

代码
int pr[N],cnt;
bool vis[N];
void init(){
	int n=1e5+50;
	for(int i=2;i<=n;i++){
		if(!vis[i]){pr[++cnt]=i;}
		for(int j=1;j<=cnt&&i*pr[j]<=n;j++){
			vis[i*pr[j]]=1;
			if(i%pr[j]==0)break;
		} 
	}
}

 

区间筛:(埃氏筛)

代码
const int maxn = 1e6+10;
typedef long long LL;
bool is_prime[maxn];  //标记a~b范围内的质数 
bool is_prime_small[maxn];  //标记 1~sqrt(n)范围内的所有质数 
LL a, b;

//对区间[a, b]内的整数执行筛法,is_prime[i-a]=true表示i是素数 
void found_prime()
{
	for(LL i=0; i*i<=b; ++i)
		is_prime_small[i] = true; 
	is_prime_small[1] = false;
	for(LL i=0; i<=b-a; ++i)
		is_prime[i] = true;
		
	for(LL i=2; i*i<=b; ++i) {
		if(is_prime_small[i]) {  // i是质数 
			for(LL j=i*i; j*j<=b; j+=i)  // 标记 sqrt(b) 以内的i的倍数 
				is_prime_small[j] = false;
			for(LL j = max(2LL, (a+i-1)/i) * i; j<=b; j+=i)  //标记[a, b]中i的倍数 
				is_prime[j-a] = false;
		}
	}	
}

 

算术基本定理:

任何一个大于 1 的正整数都能唯一分解为若干个质数的乘积。

n2 为整数,有唯一的分解式:

n=p1c1×p2c2××pmcm=i=1mpici

其中 ci 都是正整数,pi 都是质数,且满足 p1p2...pm

根据算术基本的定理,对于任意一个大于 2 的整数 n,他的正约数集合可以写作:

{p1b1×p2b2××pmbm}(0bici)

推论一: n 的正约数个数为:

(c1+1)×(c2+1)××(cm+1)=i=1m(ci+1)

推论二: n 的所有正约数之和为:

(1+p1+p12+...+p1c1)××(1+pm+pm2+...+pmcm)=i=1mj=0cipij

 

阶乘分解

对于一个数 nn! 的质因数分解:

考虑对于一个质数 pin! 中包含多少个 pi
答案是 i=1logpnnpi
对于每一个质数都用如上方式
共有 nlnn 个数,每次处理 logn 的复杂度,总复杂度 O(n)

 

求解正约数集合:

试除法 求 n 的正约数:

时间复杂度 O(n)

代码
int divisor[10010], cnt = 0;
for(int i=1; i<=sqrt(n); ++i) {
	if(n % i == 0) {
		divisor[++cnt] = i;
		if(i != n/i) divisor[++cnt] = n/i;
	}
}

推论:一个整数 n的正约数个数最多不超过 2×n

 

倍数法 求1n的正约数:

先枚举 1n 中的每一个数作为约数 d,再在 1n 寻找 d 的倍数即可。时间复杂度 O(n+n2++nn)=O(nlogn)

代码
vecotr<int> divisor[500010];
for(int i=1; i<=n; ++i) { // 先枚举约数 i
	for(int j=1; j<=n/i; ++j) //枚举 i 在 1~n 范围内的倍数 i × j
		divisor[i*j].push_back(i); // i 是 i × j 的约数
}

推论:1n 的约数个数总和大约为 nlogn 个。

 

约数研究

f(x)x 的约数个数,求 i=1nf(i)

可以枚举每一个 i[1,n]1n 中含有 ni 个约数 i 。所以答案为 i=1nni

 

gcd :

a,bN,dNda & db 则称 da,b 的公约数。

a,b 的公约数中最大的称为 a,b 的最大公约数,记为 gcd(a,b)

性质:

  • gcd(a,b)=gcd(b,a)
  • 对于 a,bNgcd(a,b)=1 则称 a,b 互质。
  • 由于任何正整数都是 00 的公约数,故 gcd(0,0) 不存在。
  • 对于 aN ,有 gcd(a,a)=a,gcd(a,0)=a
  • kZ,有 gcd(k×a,k×b)=k×gcd(a,b)

 

更相减损术:

a,bN & abgcd(a,b)=gcd(b,ab)=gcd(a,ab)

da & db,有 a=k1×d,b=k2×d ,则 (ab)=(k1k2)×d ,所以 d 也是 b,ab 的公约数,所以 gcd(a,b)=gcd(b,ab)​ 。

 

辗转相除法:

a,bN & b!=0gcd(a,b)=gcd(b,amodb)

  • a<b ,则 gcd(b,amodb)=gcd(b,a)=gcd(a,b)
  • ab ,设 a=q×b+r ,其中 0r<br=amodb 。有 a=k1×d,q×b=k2×d ,则 r=(aq×b)=(k1k2)×d ,因此 d ,也是 b,r 的公约数,故 gcd(a,b)=gcd(b,amodb)

代码:

代码
int gcd(int a, int b) {
	while(b > 0 ) {
		int x = a % b;
		a = b;
		b = x;
	}
	return a;
}

递归:

代码
int gcd(int a, int b) {
	return b ? gcd(b, a%b) : a;
}

最大复杂度 O(log(a+b))

 

lcm

a,bN,mNam & bm,则称 mab 的公倍数。

a,b 的公倍数中最小的称为 a,b 的最小公倍数,记为 lcm(a,b)

lcm(a,b)=a×bgcd(a,b)

实际代码中: lcm(a,b)=agcd(a,b)×b

 

gcd与lcm

给出某两个整数 abab)的最大公约数 GCD 和最小公倍数 LCM ,请找出满足的 ab ,使得 ba 的值最小。

LCM=a×bGCD
a×bGCD2=LCMGCD(aGCD)2LCMGCD
aGCDLCMGCD
a=aGCD ,从 LCMGCD1 来枚举 a ,当 aLCMGCD&&gcd(a,LCM/GCD/a)=1 时停止枚举。
答案即为 a=a×GCD,b=LCMa

 

CF1152C

给定两个正整数 a,b ,找到非负整数 k 使 a+kb+k 的最小公倍数最小,如有多解输出最小的 k

a>b 显然 lcm(a+k,b+k)=(a+k)(b+k)gcd(a+k,b+k)
由辗转相除法可知 gcd(a,b)=gcd(b,ab)
所以 lcm(a+k,b+k)=(a+k)(b+k)gcd(b+k,ab)
所以可以枚举 ab 的因子 w ,若 b%w=0k=0 ,否则 k=(bw+1)wb

posted @   programmingysx  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
点击右上角即可分享
微信分享提示