欧拉线性筛 和 欧拉函数的求值

PS:求逆元的部分在文章最后。。。最好也看看前边的知识吧qwq



用筛法求素数的基本思想是:把从1开始的、某一范围内的正整数从小到大顺序排列, 1不是素数,首先把它筛掉。剩下的数中选择最小的数是素数,然后去掉它的倍数。依次类推,直到筛子为空时结束。(来自 百度百科)



一般的筛法(埃拉托斯特尼筛法)的效率是O(nlglgn),但出题人卡你可就凉了。。

(就不介绍了(逃))

下面我们来说O(n)的欧拉线性筛

埃筛之所以慢,是因为有些合数被重复筛除(如:6会被2和3重复筛)

但是欧拉筛保证

每一个数p,只会被其最小的素因子mp[p]筛一次

#define R register intconst int M=1000010;
int mp[M],//mp[i] 为i的最小素因子
    prime[M],//prime[i] 代表2-n中的第i个质数
    cnt;//素数计数
inline void Prime(int n)//筛的范围
{
    for(R i=2;i<=n;i++)
    {
        if(!mp[i]) prime[++cnt]=mp[i]=i;
        for(R j=1,k=i*prime[j];j<=cnt&&prime[j]<mp[i]&&(k=i*prime[j])<=m;i++) mp[k]=prime[j];
    }
}

也有一些别的写法,如

inline void Prime(int x)
{
    for(int i=2;i<=x;i++)
    {
        if(!mp[i]) prime[++cnt]=i,mp[i]=i;
        for(int j=1;j<=cnt&&i*prime[j]<=x;j++)
        {
            mp[i*prime[j]]=prime[j];
            if(i%prime[j]==0) break;
            //if(prime[j]>=mp[i]) break;
        }
    }
}

if(i%prime[j]==0) break; 这个很重要qwq

若 i%prime[j]==0,则 i=k*prime[j](k为正整数).

如果不 break,下一个循环中的 mp(i*prime[j+1])=prime[j+1],

就是 mp(k*prime[j]*prime[j+1])=prime[j+1],

但 显然k*prime[j]*prime[j+1]的最小质因子为 prime[j] 而非 prime[j+1](prime[]数组中的素数是递增的)

所以应 break

if(prime[j]>=mp[i]) break;也可用这句话,一个意思,就是不能让 i乘上的质因子 大于 i的最小质因子


欧拉函数。。。

在数论,对正整数n,欧拉函数是少于或等于n的数中与n互质的数的数目。此函数以其首名研究者欧拉命名,它又称为Euler‘s totient function、φ函数、欧拉商数等。 例如φ(8)=4,因为1,3,5,7均和8互质。

所以求某个φ(p)可以有很朴素(朴素的不行)的求法:

//就是枚举每个素因子
inline int phi(int n)
{
    R ans=1;
    for(R i=2;i*i<=n;++i) if(n%i==0)
    {
        n/=i;
        ans*=i-1;
        while(n%i==0) n/=i,ans*=i;
    }
    if(n>1) ans*=n-1;
    return ans;
}

但如果求p∈[1,n],每个φ(p),那上面的算法就太菜了。

数论上的积性函数f(x)满足a与b互素时(a,b∈N+),f(a·b)=f(a)·f(b),f(1)=1;

而φ(p)就是一个积性函数。

此时可以利用刚学的欧拉筛

正确性:

1.φ(p)是一个积性函数,当a与b互素时,满足φ(a·b)=φ(a)·φ(b)。

2.当正整数p是素数时,φ(p)=p-1 (定义)

3.每个合数只会被筛到一次(前面说明过)。

4.当p是素数时,φ(pk)=(p-1)·φ(pk-1),因为有(p-1)个数与p互素

#define R register int
const int N=10000010;
int n,cnt,prime[N],p[N];
bool vis[N];

inline void Euler(int n)
{
    vis[1]=true;
    for(R i=2;i<=n;i++)
    {
        if(!vis[i]) prime[++cnt]=i,p[i]=i-1;
        for(R j=1;j<=cnt&&i*prime[j]<=n;j++)
        {
            vis[i*prime[j]]=true;
            if(i%prime[j]==0)
            {
                p[i*prime[j]]=p[i]*prime[j];
                break;
            }
            p[i*prime[j]]=(prime[j]-1)*p[i];
        }
    }
}//p[i]即为φ(i)


所以隆重推出......::::::

欧拉定理:

若p,a为正整数,且p,a互质,则:a^φ(p) ≡1 (mod p) (是不是有些眼熟)

其实欧拉定理相当于费马小定理的扩展

所以我们可用其求乘法逆元:

a*a^(φ(p)-1) ≡1 (mod p)

a^(φ(p)-1)即为a mod p 意义下的逆元

#include<iostream>
#include<cstdio>
#include<cctype>
#define R register int
#define ll long long
using namespace std;
static ll a,p;

inline ll q_pow(ll x,ll ind,ll mod)
{
    x%=mod;
    register ll a=1;
    for(;ind;ind>>=1,(x*=x)%=mod) if(ind&1) (a*=x)%=mod;
    return a;
}

inline int phi(int n)
{
    R ans=1;
    for(R i=2;i*i<=n;++i) if(n%i==0)
    {
        n/=i;
        ans*=i-1;
        while(n%i==0) n/=i,ans*=i;
    }
    if(n>1) ans*=n-1;
    return ans;
}

int main()
{
    scanf("%lld%lld",&a,&p);
    printf("%lld\n",q_pow(a,phi(p)-1,p));
    return 0;
}

如有错误,恳请您指正(我太菜了);如有不理解,可留言,我会尽量回复。。。(高中生(逃)。。)

by Jackpei 2019.2.13

原文地址:https://www.cnblogs.com/Jackpei/p/10372392.html

时间: 2024-11-09 19:44:27

欧拉线性筛 和 欧拉函数的求值的相关文章

欧拉线性筛法求素数(顺便实现欧拉函数的求值)

我们先来看一下最经典的埃拉特斯特尼筛法.时间复杂度为O(n loglog n) int ans[MAXN]; void Prime(int n) { int cnt=0; memset(prime,1,sizeof(prime)); prime[0]=prime[1]=0; for(int i=2;i<n;i++) { if(vis[i]) { ans[cnt++]=i;//保存素数 for(int j=i*i;j<n;j+=i)//i*i开始进行了稍微的优化 prime[j]=0;//不是素

线性筛素数(欧拉筛)+前缀和优化

关于素数的定义:在大于1的自然数中,除了1和它本身以外不再有其他因数. 判断一个数是否是素数: 1 int x; // 要求的数 2 for(int i=2;i<=sqrt(x);++i) 3 { 4 if(x%i==0) 5 { 6 cout << "这不是素数" << endl; 7 break; 8 } 9 } 埃氏筛法(时间复杂度:$O(NloglogN)$): 1 int num_prime = 0; // 素数的数量 2 int prime[5

关于在线性筛中求积性函数

蒟蒻以欧拉心算为例子,浅谈一下如何求一些较复杂的积性函数 欧拉心算: \[\sum_{i=1}^n\sum_{j=1}^n\phi(gcd(i,j))\] 与之前的一样: \[\sum_{d=1}^n\phi(d)\sum_{i=1}^{[n/d]}\sum_{j=1}^{[n/d]}[gcd(i,j)==1]\] 利用\(\mu\)函数的性质: \[\sum_{d=1}^n\phi(d)\sum_{i=1}^{[n/d]}\sum_{j=1}^{[n/d]}\sum_{k|gcd(i,j)}\

线性筛与积性函数

线性筛 最初,线性筛只是用来筛质数罢了... void sieve(int n) { static int v[N], p[N], pr; // v[i] 表示 i 的最小质因子 // p[N] 和 pr 用来存质数表 for (int i = 2; i <= n; ++i) { if (v[i] == 0) v[i] = i, p[++pr] = i; // 没被筛,是质数 for (int j = 1; j <= pr && i*p[j] <= n; ++j) { v

P2158 [SDOI2008]仪仗队 线性筛(欧拉函数和素数表)

上三角行恰好是[1,n-1]的欧拉函数 http://www.luogu.org/problem/show?pid=2158#sub 1 //#pragma comment(linker, "/STACK:167772160") 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <iostream> 6 #include <queue&g

欧拉线性筛模板

memset(mindiv,0,sizeof(mindiv)); for(int i=2;i<=n;i++){ if(!mindiv[i]) prime[++tot]=mindiv[i]=i; for(int j=1;j<=tot&&prime[j]<=mindiv[i]&&(k=prime[j]*i)<=n;j++) mindiv[k]=prime[j]; }

线性筛素数-欧拉筛法

1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 int num[100000]; 5 long long prime[5000001]; 6 bool is_prime[10000001]; 7 int N,M; 8 int cnt=1; 9 int main() 10 { 11 for(int k=0;k<10000001;k++) 12 { 13 is_prime[k]=true; 14

[洛谷P3383]线性筛素数-欧拉筛法

Description 如题,给定一个范围N,你需要处理M个某数字是否为质数的询问(每个数字均在范围1-N内) Input&Output Input 第一行包含两个正整数N.M,分别表示查询的范围和查询的个数. 接下来M行每行包含一个不小于1且不大于N的整数,即询问该数是否为质数. Output 输出包含M行,每行为Yes或No,即依次为每一个询问的结果. Solution 代码如下: #include<iostream> #include<cstring> using n

积性函数,线性筛入门 HDU - 2879

HDU - 2879HeHe 题意:He[N]为[0,N−1]范围内有多少个数满足式子x2≡x (mod N),求HeHe[N]=He[1]×……×He[N] 我是通过打表发现的he[x]=2k,k为x是质因子个数,不过这是可以通过积性函数证明的. 关于积性函数的定义: 对于正整数n的一个算术函数 f(n),若f(1)=1,且当a,b互质时,f(ab)=f(a)f(b),在数论上就称它为积性函数.若对于某积性函数 f(n) ,就算a, b不互质,也有f(ab)=f(a)f(b),则称它为完全积性