数学知识汇总

质数

定义

质数的定义为:一个数除了1和它自身以外无其他因数,这个数就为质数,否则即为合数(1既不是质数也不是合数)

质数的判定

质数的判定是一个很基础的东西,顾名思义,就是给定一个数字,判断它是不是质数
那么如何解决这个问题呢,就需要一个非常简单的算法——试除法(在后面将经常出现)
根据定义,我们只需要枚举 2 − n 2-n 2n- 1 1 1 之中是否存在 n n n的因数,如果存在,这个数即为质数,否则为合数

code
bool Pan(int x)
{
   
	if(x==1) return 0;//对1进行特殊处理
	for(int i=2;i<x;i++)
		if(x%i==0) return 0;
	return 1;
}

上述的算法中,复杂度很明显为 O ( n ) O(n) O(n),也就是说,我们最多只能在 1 s 1s 1s的时间范围内判断 1 0 8 10^8 108以内的数字是否为质数
对上述做法进行优化
将扫描的范围调整到 2 − n 2-\sqrt n 2n
为什么这样写呢
很容易考虑到一个性质——因数是成对出现的
即如果 a a a n n n的因数,那么 n / a n/a n/a也一定为 n n n的因数( a a a可以与 n / a n/a n/a相等)
a a a n / a n/a n/a这两个数中,一定有至少一个数 ≤ n \leq \sqrt n n ,所以只需要扫描到这里,就可以判断 n n n除了 1 1 1和自身以外,是否有其余的因数

code
bool Panduan(int x)
{
   
	if(x==1) return 0;//对1进行特殊处理
	for(int i=2;i<=sqrt(x);i++)
		if(x%i==0) return 0;
	return 1;
}

质数的筛选

知道了如何判定一个数是不是质数
那么怎么求 n n n以内所有的质数呢

试除法 O ( n × n ) O(n \times \sqrt n) O(n×n )

扫描 1 − n 1-n 1n中的每一个数,按照刚才所使用的试除法,判断每一个数字是不是质数

code
bool Panduan(int x)//进行n次操作
{
   
	if(x<=1) return 0;
	for(int i=2;i<=sqrt(x);i++)
		if(x%i==0) return 0;
	return 1;
}
int main()
{
   
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
		if(Panduan(i)==1)
			cout<<i<<endl;
}
埃氏筛 O ( n × l o g l o g n ) O(n\times loglogn) O(n×loglogn)

对于一个数 i i i,如果它不是质数,那一定有一个小于 i i i且不为 1 1 1的因数,假设这个因数为 j j j,那么 i i i就是 j j j的倍数,所以可以提前将 j j j小于 n n n的倍数全都标记为合数,最后没有被标记的数就是质数。

code
void Eratothenes(int n)
{
   
	prime[0]=prime[1]=1;
	for(int i=2;i<=n;i++)
		for(int j=i*2;j<=n;j+=i)
			prime[j]=1;
}

在这个代码中,没有被 p r i m e prime prime数组标记的,就为质数
但这个代码仍有可以优化的地方
对于我们上述的操作,将每一个数的倍数都进行标记,就会出现一些重复的操作,比如 36 36 36会同时被 2 , 3 , 4 , 6 , 9 , 12 , 18 2,3,4,6,9,12,18 234691218标记
对于一个已经被标记的合数 x x x x x x的倍数一定是使 x x x被标记的质数 y y y的倍数,例如 4 4 4的倍数一定是 2 2 2的倍数, 9 9 9的倍数一定是 3 3 3的倍数等
所以我们只需要标记质数的倍数,合数的倍数也就同时被标记了

code
void Eratothenes(int n)
{
   
	prime[0]=prime[1]=1;
	for(int i=2;i<=n;i++)
		if(!prime[i])
			for(int j=i*2;j<=n;j+=i)
				prime[j]=1;
}
线性筛法(欧拉筛) O ( n ) O(n) O(n)

继续考虑是否可以继续对埃氏筛进行优化
上述的优化已经大大减少了同一个数被重复标记的次数,但有些数依然会被重复标记
例如 6 6 6会同时被质数 2 2 2 3 3 3标记,虽然对时间复杂度的影响已经不大,但依然可以继续优化
首先明确目标:将一个数通过唯一的方式筛出来
可以通过算数基本定理(见下文)将任意一个正整数用唯一的一种方式筛出来
也就可以把这个数转化为这个数最小的一个质因子乘另一个数
举个例子:
30 = 2 × 3 × 5 = 2 × 15 , 36 = 2 × 2 × 3 × 3 = 2 × 18 30=2 \times 3 \times 5=2\times15,36=2\times2\times3\times3=2\times18 30=2×3×5=2×15,36=2×2×3×3=2×18
对于一个数,它所含质数中最小的一个质因子是确定的,因此,像上述例子中的拆分也是唯一的
30 = 5 × 6 = 3 × 10 = 30=5\times6=3\times10= 30=5×6=3×10= 2 × \times × 15
那么我们采用的是一种什么样的筛法呢
假如 x × y = z ( x x\times y=z(x x×y=z(x为最小的质因子 ) ) ),那么我就让 y y y来筛 z z z
这是个什么意思呢
再举个例子吧
首先 2 ( x ) 2(x) 2(x)为质数,那么由 2 ( y ) 2(y) 2(y)我可以筛出来 4 ( z ) 4(z) 4(z)是合数且最小质数为 2 ( x ) 2(x) 2(x),由 3 ( y ) 3(y) 3(y)筛出来 6 ( z ) 6(z) 6(z)是合数且最小质因子为 2 ( x ) 2(x) 2(x),由 4 ( y ) 4(y) 4(y)筛出来 8 ( z ) 8(z) 8(z)是合数且最小质因子为 2 ( x ) 2(x) 2(x)……以此类推
于是我们可以枚举 y y y x x x,然后标记 z z z
那么问题又来了, y y y x x x的枚举范围应该是多少呢?
首先来确定 y y y y y y的范围很显然应该是从 2 − n 2-n 2n,因为我们要对每一个数都进行处理呀
那么 x x x的范围呢,是不是应该是所有 ≤ y \leq y y的最小质因子的质数
听起来可能很绕对吧
那我们再举个例子
y = 175 y=175 y=175,可以把 y y y划分为 y = 5 × 5 × 7 y=5\times 5\times 7 y=5×5×7,所以 x x x的范围就应该是 ≤ 5 \leq 5 5的质数
再换个简单的例子
y = 15 y=15 y=15,可以把 y y y划分为 y = 3 × 5 y=3\times 5 y=3×5,所以 x x x的范围就应该是 ≤ 3 \leq 3 3的质数,即 2 2 2 3 3 3(标记了 30 30 30 45 45 45的最小质因子为x)
那为什么只有 2 2 2 3 3 3,难道 3 3 3以后的质数就不管了吗?
x = 5 x=5 x=5时, 75 75 75要留着给谁标记呢?
答案是 25 25 25,因为 75 75 75的最小质因子为 3 3 3,而不是 5 5 5(现在的 x x x)
所以 75 75 75根本轮不上 15 15 15来管
解释一下具体的证明过程
现在 y = 3 × 5 y=3\times 5 y=3×5,假如 x > 3 x>3 x>3,那 z = x × 3 × 5 z=x \times 3\times5 z=x×3×5 z z z现在的最小质因子还是 x x x吗?是不是已经变为 y y y的最小质因子 3 3 3
因此,当 x x x大于 y y y的最小质因子时, z z z的最小质因子就不归 x x x管了!

code
int v[maxn];//v数组存储i的最小质因子
int prime[maxn]//prime数组存储已经筛出来的质数
void primes(int n)
{
   
	int m=0;//质数的数量
	for(int y=2;y<=n;y++)
	{
   
		if(v[y]==0)//如果y还没有最小质因数(y为质数)
		{
   
			v[y]=y;//y的最小质因数赋值为它自身
			prime[++m]=y;//储存这个质数
		}
		for(int i=1;i<=m;i++)
		{
   
			int x=prime[i];
			if(x>v[y]) break;//如果x>y的最小质因子,就停止循环
			if(x*y>n) break;//如果超出n的范围,停止循环
			int z=x*y;
			v[z]=x;
		}
	}
}

质因数分解

在“质数的筛选”中提到过算术基本定理,即任意一个大于 1 1 1的正整数都能唯一分解为有限个质数的乘积
所以可以使用试除法 O ( n ) O(\sqrt n) O(n )来实现质因数分解
操作很简单,从最小的质数 2 2 2开始,一直到 n \sqrt n n ,只要可以整除当前的数,就一直除以这个数,直到不能整除。

For example:
初始的 n n n 120 120 120,i从 2 2 2循环到 n \sqrt n n
n n n可以整除 2 2 2,此时 n = 60 n=60 n=60
n n n可以整除 2 2 2,此时 n = 30 n=30 n=30
n n n可以整除 2 2 2,此时 n = 15 n=15 n=15
n n n不能整除 2 2 2 i + + i++ i++
n n n可以整除 3 3 3,此时 n = 5 n=5 n=5
n n n不能整除 3 3 3 i + + i++ i++
n n n不能整除 4 4 4 i + + i++ i++
n n n可以整除 5 5 5,此时 n = 1 n=1 n=1
n = 1 n=1 n=1,结束循环

观察我们除以过的数字,分别是 2 , 2 , 2 , 3 , 5 2,2,2,3,5 22235
所以 120 = 2 × 2 × 2 × 3 × 5 120=2\times2\times2\times3\times5 120=2×2×2×3×5

来解释一下这个思路里的一些细节问题
1.循环到 n \sqrt n n 的原因,还是像0x31 T1中提到的,如果 n n n不为质数,那 n n n就会有除了自己和 1 1 1以外的因数,假设这个因数为 i i i, 那么 n / i n/i n/i也一定是 n n n的因数, i i i n / i n/i n/i之间一定就会有一个数 ≤ n \leq \sqrt n n ,所以只需要扫描到 n \sqrt n n ,就可以找到除了 1 1 1 n n n以外是否有其他的因数,即 n n n是否为质数,满足我们寻找n的质因子的目的。
2.对于每一个 i i i 都进行整除的操作,是否会有为合数的i被统计为质因数?答案是不会的,上面的例子中, 120 120 120可以整除 4 4 4,但当 i = 4 i=4 i=4时, n n n就已经变为了 5 5 5,已经不能整除 4 4 4了,出现这种情况的原因是, 4 4 4作为一个合数,也可以进行质因数分解,例如把 4 4 4分解为 2 × 2 2\times 2 2×2,所以 n / 4 n/4 n/4就等价于 n / 2 / 2 n/2/2 n/2/2,当 i = 2 i=2 i=2时,我们就已经把所有的质因子 2 2 2都提出来了,因此当 i i i 为合数时, n n n一定不会整除 i i i
3. n n n的值是否可以一直改变?是的,因为我们要找的始终是现在的 n n n的质因子,所以 s q r t ( n ) sqrt(n) sqrt(n)也在一直改变。

code
int p[maxn],c[maxn];//p为底数,c为指数 
void zhiyinshufenjie(int n)
{
   
	int m=0;//计数器 
	for(int i=2;i<=sqrt(n);i++)
	{
   
		if(n%i==0)//如果可以整除i 
		{
   
			p[++m]=i;//底数为i 
			while(n%i==0) n/=i,c[m]++;//指数+1 
		}
	}
	if(n>1) //n现在自身为质数
	{
   
		p[++m]=n;
		c[m]++;
	} 
	for(int i=1;i<=m;i++) cout<<p[i]<<' '<<c[i]<<endl;
}
例题

Prime Distance
阶乘分解

约数

算术基本定理及其推论

算术基本定理:

任何一个大于1的正整数都能唯一分解为有限个质数的乘积,可写作
N = p 1 c 1 p 2 c 2 … p m c m N=p_1^{c_1}p_2^{c_2}\dots p_m^{c_m} N=p1c1p2c2pmcm
其中 c i c_i ci都是正整数, p i p_i pi都是质数,且满足 p 1 < p 2 < ⋯ < p m p_1<p_2<\dots <p_m p1<p

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值