欧拉筛法
欧拉筛法的数学原理:
欧拉函数:在数论,对正整数n,欧拉函数是小于n的正整数中与n互质的数的数目(φ(1)=1)。此函数以其首名研究者欧拉命名(Euler’s totient function),它又称为Euler’s totient function、φ函数、欧拉商数等。 例如φ(8)=4,因为1,3,5,7均和8互质。
欧拉筛法可以用于对给定区间内的所有素数进行打表,欧拉筛法大幅度提升了程序的效率。
时间复杂度:O(n)
代码:
#include <iostream> //该代码用于对2-maxm(这里maxm是50)中的所有素数进行打表
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int maxm = 50;
int p[maxm];
bool vis[maxm];
int num = 1;
void Prime()
{
memset(vis,true,sizeof(vis)); //初始化vis数组,用来标记是否为素数
for(int i = 2 ; i <= maxm ; i++)
{
if(vis[i]) //如果i为素数,vis[i]则为true,将i存入p数组
p[num++] = i;
for(int j = 2 ; j < num ; j++)
{
if(i*p[j] > maxm) //超出范围直接跳出
break;
vis[i*p[j]] = false; //对非素数进行标记
if(i % p[j] == 0) //若当前素数为i的最小素因子直接跳出
break;
}
}
}
void Output()
{
for(int i = 1 ; i < num ; i++)
{
cout << p[i] << " ";
if(i % 5 == 0)
cout << "\n";
}
}
int main()
{
Prime();
Output();
return 0;
}
欧拉筛法的证明:
设合数?最小素因子为?,它的另一个大于?的素因子为?′,令?=??=?′?′。 观察上面程序片段,可以发现?循环到素因子?时,合数?第一次被标记(若循环到?之前已经跳出循环,说明? 有更小的素因子)。若也被?′标记,则是在这之前(因为?′<?),考虑?循环到?′,注意到?=??=?′?′且?和?′为不同的素因子,因此?|?′,所以当?循环到素因子?后结束,不会循环到?′,这就说明不会被?′筛去。
欧拉筛法的应用:
L – Goldbach’s Conjecture
试题来源:Ulm Local 1998
在线测试:POJ 2262,ZOJ 1951,UVA 543
In 1742, Christian Goldbach, a German amateur mathematician, sent a letter to Leonhard Euler in which he made the following conjecture:
Every even number greater than 4 can be written as the sum of two odd prime numbers.
For example:
8 = 3 + 5. Both 3 and 5 are odd prime numbers.
20 = 3 + 17 = 7 + 13.
42 = 5 + 37 = 11 + 31 = 13 + 29 = 19 + 23.
Today it is still unproven whether the conjecture is right. (Oh wait, I have the proof of course, but it is too long to write it on the margin of this page.)
Anyway, your task is now to verify Goldbach’s conjecture for all even numbers less than a million.
Input
The input will contain one or more test cases.
Each test case consists of one even integer n with 6 <= n < 1000000.
Input will be terminated by a value of 0 for n.
Output
For each test case, print one line of the form n = a + b, where a and b are odd primes. Numbers and operators should be separated by exactly one blank like in the sample output below. If there is more than one pair of odd primes adding up to n, choose the pair where the difference b – a is maximized. If there is no such pair, print a line saying “Goldbach’s conjecture is wrong.”
Sample Input
8
20
42
0
Sample Output
8 = 3 + 5
20 = 3 + 17
42 = 5 + 37
先用欧拉筛法对2-1e6之间的素数进行打表,然后便利2到n之间的元素,利用哈希散列找下标为n-i和i都是true类型的元素,直接输出即可。
AC代码:
#include <iostream>
#include <cstring>
using namespace std;
typedef long long LL;
const int maxm = 1e6;
int k = 1;
LL p[maxm];
bool vis[maxm];
void Prime() //欧拉筛法
{
memset(vis,true,sizeof(vis));
for(int i = 2 ; i <= maxm ; i++)
{
if(vis[i])
p[k++] = i;
for(int j = 1 ; j < k ; j++)
{
if(i*p[j] > maxm)
break;
vis[i*p[j]] = false;
if(i % p[j] == 0)
break;
}
}
}
int main()
{
Prime();
LL t;
while(cin >> t)
{
if(t == 0)
break;
for(int i = 3 ; i <= maxm ; i++)
{
if(vis[i] && vis[t-i])
{
cout << t << " = " << i << " + " << t-i << endl;
break;
}
}
}
return 0;
}