1.最小公倍数、最大公约数
最小公倍数的求算一般依赖于最大公约数的获取。
假设求12和18的最小公倍数,直觉告诉我们是36,解释起来就是:
18/12!=0,18%12==6;
12%6==0;
最大公约数即为6.
最小公倍数=两数乘积/最大公约数
即12*18/6=36.可见,核心函数是最大公约数的求算函数.
最大公约数的求算一般有辗转相除法:
int gys(int x, int y)
{
int r = x % y;
while (r != 0)
{
x = y;
y = r;
r = x % y;
}
return y;//最大公约数实现
}
那么写最小公倍数就非常简单了,两函数并用即可:
int gbs()
{
return x * y / gys(x, y);
}
2.素数筛函数
素数筛的实现比较灵活,有多种方法都可以达成。按照一本通上介绍的方法分题型展开:
(1)分界筛,埃拉托斯特尼筛
它针对求某区间的质数,尤以2-n为方便。
#include<iostream>
#include<cstring>
#include<cmath>
#include<iomanip>
#include<algorithm>
using namespace std;
bool prime[101];
int t;
int main()
{
for (int i = 0; i <= 100; ++i)
{
prime[i] = true;
}//把bool数组内所有元素标作true
prime[1] = false;
//同样可以通过memset(prime,1,sizeof(prime))实现.
for (int i = 2; i <= sqrt(100); ++i)
{
if (prime[i])//筛走非质数,跳过已标记的质数的倍数
for (int j = 2; j <= 100 / i; ++j)
prime[i * j] = false;//能相乘就不是质数。标记false.
}
//sqrt()是一个非常巧妙的技巧。他可以优化算法.
//后面的j<=100/i其实直接就求出了区间内倍数的个数,提高了效率
for (int w = 2; w <= 100; ++w)
{
if (prime[w])
{
cout <<w<<" ";//每行五个数
++t;
if (t % 5 == 0)
cout << endl;
}
}
return 0;
}
sqrt(n)对朴素算法进行优化.
sqrt(n)怎么优化的呢?
首先明确我们需要找两因子相乘也就是标为false的合数;
我们知道如果要找两个因子相乘等于n,两因子必定分布在sqrt(n)两侧;可以作简单证明:
假设{n∈R|n>0},k*k=n,k=sqrt(n);
那么若使两因子双双出现在n的右侧,k*k=sqrt(n)*sqrt(n)>n;明显违反了定义;
同样可证双因子落于左侧的情况.
所以两因子只可能是分布在两侧,或者恰好相等且等于sqrt(n).
那么换句话说,我们可以通过sqrt(n)这一分界线确定k1的位置范围,之后遍历另一因子的位置就可以标记完;
(遍历一次)另一因子的范围确定基于n/i,也就是说基于k1。它有点像握手问题。n/i的一直在缩小,因为i也就是第一个因子在增大,时间越往后需要标记的越少。这样利用分界线减少了计算量,避免了重复标记,时间复杂度减小(特别是数据量大的时候替代试除法),效率提高。
所以在实际筛数的时候,要灵活使用sqrt(n).
埃拉托斯特尼筛法:
const int N = 1e5 + 7;
int p[N];
bool st[N];
int idx;
void prime()
{
int goal = 1e5;//1e5是筛的范围
for(int i = 2; i < goal; ++i )
{
if(!st[i])
p[idx ++] = i;
for(int j = 0; p[j] <= goal / i; ++j )
{
st[p[j] * i] = 1;
if(i % p[j] == 0)
break;
}
}
}
(2)单个质数筛模块
一本通上的例子微调后:
//我们想要判断x是不是素数.
int prime(int x)
{
if (x == 1)
return 0;
else if (x == 2)
return 1;
else
{
int j = 2;
while (j <= sqrt(x)&&x%j!=0)
j++;
if (x % j == 0)
return 0;
else
return 1;
}
}
但该代码往往只能判断一个数是不是质数,现实操作更可能需要遍历区间内所有质数,且使用数组。所以还是更推荐以上两种筛法。
总结一下:
分界筛注重sqrt(n)的分界作用和合数标记;
埃筛注重构造合数标记;
单个质数筛注重sqrt(n)的分界作用.
理解了这些构造筛子就会很快.