埃氏筛法
第一种
这种方法好处是每个素数的位置标记,可以直接取下标
int visit[maxn]; // 0 表示素数 1 表示非素数
void Prime(){
memset(visit,0,sizeof(visit); //初始化都是素数
visit[0] = visit[1] = 1; //0 和 1不是素数
for (int i = 2; i <= maxn; i++) {
if (!visit[i]) { //如果i是素数,让i的所有倍数都不是素数
for (int j = i*i; j <= maxn; j += i) {
visit[j] = 1;
}
}
}
}
第二种
这种方法的好处是素数是连续的,用vector保存,不耗费内存
const int maxn=1005;
bool bk[maxn];
vector<int> v;
void find_Prime()
{
//初始化, 打表
memset(bk, 1, sizeof(bk));
for(ll i = 2; i < maxn; i++)
{
for(ll j = i * i; j < maxn; j += i)
{
bk[j] = 0;
}
}
//取出相应的素数
for(ll i = 2; i < maxn; i++)
{
if(bk[i] == 1)
v.push_back(i);
}
}
欧拉筛法
这种方法的好处是素数是连续的
const int maxn=10000005;
int prime[maxn],visit[maxn];
void Prime(){
memset(visit,0,sizeof(visit));
memset(prime, 0,sizeof(prime));
for (int i = 2;i <= maxn; i++) {
cout<<" i = "<<i<<endl;
if (!visit[i]) {
prime[++prime[0]] = i; //纪录素数, 这个prime[0] 相当于 cnt,用来计数
}
for (int j = 1; j <=prime[0] && i*prime[j] <= maxn; j++) {
// cout<<" j = "<<j<<" prime["<<j<<"]"<<" = "<<prime[j]<<" i*prime[j] = "<<i*prime[j]<<endl;
visit[i*prime[j]] = 1;
if (i % prime[j] == 0) {
break;
}
}
}
}
欧拉筛 求10亿以上的素数
const int maxn=100000;
int prime[maxn],visit[maxn];
void Prime(){
memset(visit,0,sizeof(visit));
memset(prime, 0,sizeof(prime));
for (int i = 2;i <= maxn; i++) {
cout<<" i = "<<i<<endl;
if (!visit[i]) {
prime[++prime[0]] = i; //纪录素数, 这个prime[0] 相当于 cnt,用来计数
}
for (int j = 1; j <=prime[0] && i*prime[j] <= maxn; j++) {
// cout<<" j = "<<j<<" prime["<<j<<"]"<<" = "<<prime[j]<<" i*prime[j] = "<<i*prime[j]<<endl;
visit[i*prime[j]] = 1;
if (i % prime[j] == 0) {
break;
}
}
}
}
bool prime3(long long n)
{
long long i;
for(i=1;i<=prime[0];i++)
{
if(n%(prime[i])==0)
{
return false;
}
}
return true;
}
int main()
{
Prime();
long long j=1;
for(long long i=1000000000; i<10000000000; i++)
if(prime3(i)!=false)
printf("%lld : %lld\n",j++,i);
}
欧拉函数求法
就是对于一个正整数n,小于n且和n互质的正整数(包括1)的个数,记作φ(n) 。
欧拉函数的通式:φ(n)=n(1-1/p1)(1-1/p2)(1-1/p3)*(1-1/p4)……(1-1/pn)*
其中p1, p2……pn为n的所有质因数,n是不为0的整数。φ(1)=1(唯一和1互质的数就是1本身)。
ll eular(ll n)
{
ll ans = n;
for(int i=2; i*i <= n; ++i)
{
if(n%i == 0)
{
ans = ans/i*(i-1);
while(n%i == 0)
n/=i;
}
}
if(n > 1) ans = ans/n*(n-1);
return ans;
}
欧拉筛加欧拉函数求法
void euler(int n)
{
phi[1]=1;//1要特判
for (int i=2;i<=n;i++)
{
if (flag[i]==0)//这代表i是质数
{
prime[++num]=i;
phi[i]=i-1;
}
for (int j=1;j<=num&&prime[j]*i<=n;j++)//经典的欧拉筛写法
{
flag[i*prime[j]]=1;//先把这个合数标记掉
if (i%prime[j]==0)
{
phi[i*prime[j]]=phi[i]*prime[j];//若prime[j]是i的质因子,则根据计算公式,i已经包括i*prime[j]的所有质因子
break;//经典欧拉筛的核心语句,这样能保证每个数只会被自己最小的因子筛掉一次
}
else phi[i*prime[j]]=phi[i]*phi[prime[j]];//利用了欧拉函数是个积性函数的性质
}
}
}
欧拉函数的一些性质:
① 当m,n互质时,有phi(m*n)= phi(m)*phi(n);
② 若i%p==0,有phi(i*p) = p * phi(i);
③ 对于互质x与p,有x^phi§≡1(mod p),因此x的逆元为x^(phi§-1),即欧拉定理。
(特别地,当p为质数时,phi(p)=p-1,此时逆元为x^(p-2),即费马小定理)
④ 当n为奇数时,phi(2n)=phi(n)
⑤ 若x与p互质,则p-x也与p互质,因此小于p且与p互质的数之和为phi(x)*x/2;
⑥N>1,不大于N且和N互素的所有正整数的和是 1/2 *N *eular(N)。
⑦若(N%a == 0 && (N/a)%a==0) 则有:E(N)=E(N/a)*a;
⑧若(N%a==0 && (N/a)%a!=0) 则有:E(N)=E(N/a)*(a-1);