线性(欧拉)筛&欧拉函数

线性筛法

what is 线性筛??就是基于最基本的筛法的优化。

在基础的筛法上,我们发现有的数字会被重复筛,例如6既会被2枚举到也会被3枚举到,必然有重复运算。

我们的做法就是让每一个数的最小因数筛。

\(FOR\) \(EXAMPLE:\)

有一个数\(2 * 2 * 3 * 5\)

有另一个数 \(3 * 3 * 3* 5\)

那么第一个数枚举到3的话,筛到的数字是\(2 * 2 * 3 * 3 * 5\)

但是在第二个数字再次枚举的时候 枚举到2时 也会枚举到\(2 * 2 * 3 * 3 * 5\)

因此,维护这个最小质因数即可。

怎么维护??

当\(i\) \(mod\) \(这个质因数\) \(=0\) 说明是质因数,第一次枚举到就要\(break\),这样就保证了一定会被最小素因数给筛。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n,cnt=0;
    int prime[10000]={};//用来存储素数
    int Vis[10000]={};//用来判断是否是素数
    cin>>n;
    for (int i=2;i<=n;i++)
    {
        if (Vis[i]==0) prime[++cnt]=i;//如果没有被标记过
        for (int j=1;j<=cnt&&i*prime[j]<=n;j++)//用i去乘上每一个已经求过的素数
        {
            Vis[i*prime[j]]=1;//标记素数
            if (i%prime[j]==0) break;//下面再解释
        }
    }
    for (int i=2;i<=n;i++)
        if (Vis[i]==0) cout<<i<<‘ ‘;
    return 0;
} 

一、欧拉函数概念

欧拉函数,是表示1~n中与n互质的元素的个数,记为\(φ(n)\)。

二、性质

  • 如果n为某一素数p,显然\(φ(p)\)为p-1
  • 如果n为某一素数的幂次,那么: \[\phi(p^a)=(p-1)*p^ {a-1}\]

    我们可以来推导次函数的求法

    我们先将n分解质因数得:

    \[n=a1^{b1}*a2^{b2}*a3^{b3}*……*ak^{bk}\]

因为φ(n)求的是与n互质的数的个数,所以其中不能有n的因数,即不能出现a1,a2,a3……ak的倍数。

那么我们来转换思路,n个数之中存在多少个a1的倍数,多少个a2的倍数……多少个ak的倍数呢?

显然有n/a1个a1的倍数,n/a2个a2的倍数……有n/ak个ak的倍数。

所以\(φ(n)=n-\frac{1}{a1} -\frac{1}{a2}-\frac{1}{a3}-……-\frac{1}{ak}\)

将n提取出来得到:

\[φ(n)=n*(1-\frac{1}{a1})*(1-\frac{1}{a2})*(1-\frac{1}{a3})*……*(1-\frac{1}{ak})\]

于是欧拉函数的公式就这么推导出来了

还有如下性质:

  • 如果i mod p=0,那么\(φ(i*p)=p*φ(i)\)

    证明:

    对于公式\[φ(1)=n*(1-\frac{1}{a1})*(1-\frac{1}{a2})*(1-\frac{1}{a3})*……*(1-\frac{1}{ak})\]

    得到

    \[φ(n)=n*p*(1-\frac{1}{a1})*(1-\frac{1}{a2})*(1-\frac{1}{a3})*……*(1-\frac{1}{ak})\]

    因为p已经是i的因数,后半部分不需要添加

    因此得证。

  • 函数的积性,\(φ(i*j)=φ(i)*φ(j)\)
  • 如果i mod p≠0,那么\(φ(i*p)=φ(i)*(p-1)\)

    根据

    \[φ(n)=n*(1-\frac{1}{a1})*(1-\frac{1}{a2})*(1-\frac{1}{a3})*……*(1-\frac{1}{ak})\]

    得到

    \[φ(n)=n*p*(1-\frac{1}{a1})*(1-\frac{1}{a2})*(1-\frac{1}{a3})*……*(1-\frac{1}{ak})*(1-\frac{1}{p})\]

    因为p不是i的因数,因此最后要加上\((1-\frac{n}{ak})\)部分。

    证明完成。

三、求法

下面给两种求法。

\(1\).公式法

根据公式\(φ(n)=n*(1-\frac{1}{a1})*(1-\frac{1}{a2})*(1-\frac{1}{a3})*……*(1-\frac{1}{ak})*(1-\frac{1}{p})\)

inline LL eular(LL x)
{
    LL sum=x,y=x;
    for (LL i=2;i*i<=y;++i)
    {
        if (x%i!=0) continue;
        sum=sum/i*(i-1);
        while (x%i==0) x/=i;
    }
    if (x>=2) sum=sum/x*(x-1);
    return sum;
}
//公式求x欧拉函数 

\(2\).线性筛求欧拉函数

根据三条性质推导即可。

线性筛中每一个数字最多只会被筛一次,因此正好可以对每一个数字求欧拉函数。

线性筛正好是由小的数字筛到大的数字 or 正好是指数

前者用后两条性质 后者用第一条性质即可。

三条性质如下:

  • 如果n为某一素数的幂次,那么: \(\phi(p^a)=(p-1)*p^ {a-1}\)
  • 如果i mod p=0,那么\(φ(i*p)=p*φ(i)\)
  • 如果i mod p≠0,那么\(φ(i*p)=φ(i)*(p-1)\)
inline void findphi(void)
{
    phi[1]=1,prm[1]=0;
    for (LL i=2;i<=n;++i)
    {
        if (!v[i]) { prm[++cnt]=i, phi[i]=i-1; }
        for (LL j=1;j<=cnt && i*prm[j]<=n;++j)
        {
            v[i*prm[j]]=1;
            if (i%prm[j]==0) { phi[i*prm[j]]=phi[i]*prm[j]; break; }
            if (i%prm[j]!=0) phi[i*prm[j]]=phi[i]*(prm[j]-1);
        }
    }
    return;
} 

后记

部分参考hkh大佬的博客。

在此表示感谢!

如有纰漏请读者指正!

<\font>

原文地址:https://www.cnblogs.com/pigzhouyb/p/10119722.html

时间: 2024-10-08 21:05:45

线性(欧拉)筛&欧拉函数的相关文章

欧拉筛 + 欧拉函数

1 /** 2 * Fuck you. 3 * I love you too. 4 */ 5 #include<bits/stdc++.h> 6 #define lson i<<2 7 #define rson i<<2|1 8 #define LS l,mid,lson 9 #define RS mid+1,r,rson 10 #define mem(a,x) memset(a,x,sizeof(a)) 11 #define gcd(a,b) __gcd(a,b) 1

The Euler function(线性筛欧拉函数)

/* 题意:(n)表示小于n与n互质的数有多少个,给你两个数a,b让你计算a+(a+1)+(a+2)+......+b; 初步思路:暴力搞一下,打表 #放弃:打了十几分钟没打完 #改进:欧拉函数:具体证明看po主的博客 ^0^ #超时:这里直接用欧拉函数暴力搞还是不可以的,用到线性筛欧拉函数,这里总和爆int,要用long long */ #include<bits/stdc++.h> #define ll long long using namespace std; /***********

数论线性筛总结 (素数筛,欧拉函数筛,莫比乌斯函数筛,前n个数的约数个数筛)

线性筛 线性筛在数论中起着至关重要的作用,可以大大降低求解一些问题的时间复杂度,使用线性筛有个前提(除了素数筛)所求函数必须是数论上定义的积性函数,即对于正整数n的一个算术函数 f(n),若f(1)=1,且当a,b互质时f(ab)=f(a)f(b),在数论上就称它为积性函数,若a,b不互质也满足的话则称作完全积性函数,下面说明每个筛子是怎么筛的. 最基础的是素数筛,其它三个筛都是以素数筛为前提 素数筛 void get_prime() { int pnum = 0; for(int i = 2;

质因数分解+欧拉筛+线性基

质因数分解: for(int i=2;i*i<=n;i++){ if(n%i==0) p.push_back(i); while(n%i==0) n/=i; } if(n!=1) p.push_back(n); 欧拉函数(线性筛): //欧拉函数 phi[x]代表[1,x]种与x互质的数的个数 void getphi() { phi[1]=1;int cnt=0; for(int i=2;i<=N;i++){ if(!vis[i]){prime[++cnt]=i;phi[i]=i-1;} fo

noip复习——线性筛(欧拉筛)

整数的唯一分解定理: \(\forall A\in \mathbb {N} ,\,A>1\quad \exists \prod _{i=1}^{s}p_{i}^{a_{i}}=A\),其中\({\displaystyle p_{1}<p_{2}<p_{3}<\cdots <p_{s}}\)而且 \(p_{i}\)是一个质数, \(a_{i}\in \mathbb {Z} ^{+}\)(摘自维基百科) 欧拉筛通过使每个整数只会被它的最小质因子筛到来保证时间复杂度,可以用来筛质数

线性筛素数(欧拉筛)

线性筛素数(欧拉筛) 欧拉筛为啥是\(O(n)\)的呢?我们先来看看代码. #include <cstdio> using namespace std; const int maxn=10000000; int n, m, prime[maxn], isnt_prime[maxn], tot; void get_prime(int n){ isnt_prime[0]=isnt_prime[1]=1; for (int i=2; i<=n; ++i){ //当前数是所有数小于n的数而不只是

Dirichlet&#39;s Theorem on Arithmetic Progressions POJ - 3006 线性欧拉筛

题意 给出a d n    给出数列 a,a+d,a+2d,a+3d......a+kd 问第n个数是几 保证答案不溢出 直接线性筛模拟即可 1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 bool Is_Primes[1000005]; 5 int Primes[1000005]; 6 int A[1000005]; 7 int cnt; 8 void Prime(int n){ 9 cnt=0; 1

Goldbach&#39;s Conjecture POJ - 2262 线性欧拉筛水题 哥德巴赫猜想

题意 哥德巴赫猜想:任一大于2的数都可以分为两个质数之和 给一个n 分成两个质数之和 线行筛打表即可 可以拿一个数组当桶标记一下a[i]  i这个数是不是素数  在线性筛后面加个装桶循环即可 #include<cstdio> #include<cstring> using namespace std; bool Is_Primes[1000005]; int Primes[1000005]; int cnt; void Prime(int n){ cnt=0; memset(Is_

hdu2421-Deciphering Password-(欧拉筛+唯一分解定理+积性函数+立方求和公式)

Deciphering Password Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2357    Accepted Submission(s): 670 Problem Description Xiaoming has just come up with a new way for encryption, by calculati