素数筛,欧拉函数

本文详细介绍了三种常见的素数筛法——埃氏筛法、欧式筛法和快速分解质因数,并探讨了欧拉函数在计算互质数中的应用。通过这些算法,可以有效地找出一定范围内的素数并计算特定数的欧拉函数值。此外,还讨论了欧拉降幂和整除分块等优化技巧,对算法效率提升有显著作用。
摘要由CSDN通过智能技术生成

素数筛:

1.埃氏筛法(时间复杂度O(nlogn))

const int maxn=1e4+10;
int prime[maxn],pnum=0;//prime数组存放所有素数,pnum为素数个数 
bool p[maxn];//如果i为素数,则p[i]为false,否则p[i]为true 
void find_prime(){
	for(int i=2;i<maxn;i++){
		if(p[i]==false){
			prime[pnum++]=i;
			for(int j=i+i;j<maxn;j+=i){
				//筛去i的倍数 
				p[j]=true;
			}
		}
	}
}

2.欧式筛法(时间复杂度O(n)) 每个合数都由其最小素因子筛去

int prime[maxn],tot;
bool vis[maxn];
void isprime(){
	for(int i=2;i<maxn;i++){
		if(!vis[i]){
			prime[tot++]=i;
		}
		for(int j=0;j<tot;j++){
			if(i*prime[j]>maxn) break;//判断是否越界 
			vis[i*prime[j]]=1;//筛掉合数 
			if(i%prime[j]==0) break;//判断因子是否包含素因子 
		}
	}
}

3.快速分解质因数

先预处理质因数,然后枚举质因数,原先的写法是枚举i,这样会有中间不是质因数的循环情况,相当于跳过了不是质因数的情况,在自然数中1-n随机选取一个是质因数的情况大致是1/ln(n),所以这一步相当于优化了log2(n)倍虽然可能只有十几倍但是当数据范围取到2e6的时候nsqrt(n)是会超时的,加上这一步优化就可以过题了

void init(){
	for(int i=2;i<=maxn-5;i++){
		if(!vis[i]){
			prime[++cnt]=i;
		}
		for(int j=1;j<=cnt;j++){
			if(prime[j]*i>maxn){
				break;
			}
			vis[prime[j]*i]=1;
			if(i%prime[j]==0){
				break;
			}
		}
	}
}
int fenjie(int x,int pos){
	int w=0;
	for(int i=1;i<=cnt&&prime[i]*prime[i]<=x;i++){
		if(x%prime[i]==0){
			w++;
			ans+=(pos-last[prime[i]]-1)*(n-pos+1);
			last[prime[i]]=pos;
			while(x%prime[i]==0){
				x/=prime[i];
			}
		}
	}
	if(x>1){
		w++;
		ans+=(pos-last[x]-1)*(n-pos+1);
		last[x]=pos;
	}
	return w;
}

欧拉函数:

任意给定正整数n,请问在小于等于n的正整数之中,有多少个与n构成互质关系?(比如,在1到8之中,有多少个数与8构成互质关系?) 计算这个值的方法就叫做欧拉函数,以φ(n)表示。在1到8之中,与8形成互质关系的是1、3、5、7,所以 φ(n) = 4。

第一种情况 如果n=1,则 φ(1) = 1 。因为1与任何数(包括自身)都构成互质关系。

第二种情况 如果n是质数,则 φ(n)=n-1 。因为质数与小于它的每一个数,都构成互质关系。比如5与1、2、3、4都构成互质关系。

第三种情况 如果n是质数的某一个次方,即 n = p^k (p为质数,k为大于等于1的整数),则

比如 φ(8) = φ(2^3) =2^3 - 2^2 = 8 -4 = 4。 这是因为只有当一个数不包含质数p,才可能与n互质。而包含质数p的数一共有p^(k-1)个,即1×p、2×p、3×p、...、p^(k-1)×p,把它们去除,剩下的就是与n互质的数。 上面的式子还可以写成下面的形式:

可以看出,上面的第二种情况是 k=1 时的特例。

第四种情况 如果n可以分解成两个互质的整数之积,n = p1 × p2 则 φ(n) = φ(p1p2) = φ(p1)φ(p2) 

即积的欧拉函数等于各个因子的欧拉函数之积。比如,φ(56)=φ(8×7)=φ(8)×φ(7)=4×6=24。 这一条的证明要用到"中国剩余定理"

第五种情况

 求1-n中与n互质的数的个数 板子

#include<bits/stdc++.h>
using namespace std;

int n,a,res;

int main()
{
    cin>>n;
    while(n -- )
    {
        cin>>a;
        res = a;
        for(int i = 2; i <= sqrt(a); i ++ )//分解质因数
        {
            if(a % i == 0)
            {
                res = res / i * (i - 1);//等于 res *= (1 - (1 / i))
                while(a % i == 0)//但是1 / i是小数,而res是i的倍数,所以上式一定是整数
                a /= i;
            }
        }
        if(a > 1)  //到了这一步a自己就是质因数
        res = res / a * (a - 1);
        cout<<res<<endl;
    }
    return 0;
}

线性求1-n中各个数的欧拉函数 板子

/*
特性 :
1.若a为质数,phi[a]=a-1;
2.若a为质数,b%a==0,phi[a*b]=phi[b]*a;
3.若a为质数并且a,b互质,phi[a*b]=phi[b]*phi[a]
*/
int main(){
	phi[1]=1;
	for(int i=2;i<=n;i++){
		if(!m[i]){
			p[++pump]=i;
			phi[i]=i-1; //性质1
		}
		for(int j=1;j<=pump&&p[j]*i<=n;j++){
			m[p[j]*i]=i;
			if(i%p[j]==0){ 
				phi[p[j]*i]=phi[i]*p[j]; //性质2
				break;
			}
			else phi[p[j]*i]=phi[i]*phi[p[j]]; //性质3 
		}
	}
}

附:

知识:
① 乘性函数:如果对于任意的正整数n和m,且n和m互素,函数f()有f(n*m)=f(n)*f(m)。
② 如果一个函数f是乘性函数,那么它的和函数F(n)=f(d1)+f(d2)+....+f(dk)也是乘性函数,其中 di | n (即n%di==0)
③ 如果n和m互素,gcd(i,n*m)=gcd(i,n)*gcd(i,m),所有gcd()函数乘性函数。
④ 设phi()是欧拉函数,即phi(n)表示小于n的正整数中与n素数的个数,欧拉函数phi()也是乘性函数。
⑤ 关于欧拉函数有定理:设p是素数,a是一个正整数,则 phi(p^a)=p^a - p^(a-1)。

poj-2480

题意:给一个n,求所有的gcd(i,n)之和,其中1<= i <= n.

trick:设gcd(i,n)==p 即最大公因数为p 则i/p与n/p互质 那么等价于1-n中满足i/p与n/p互质的数的个数=phi(n/p) 再枚举因数p即可求解

#include<cstdio>
#include<cmath>
#define ll long long
ll n,ans,i;
ll euler(int x)
{
    int res=x;
    for(int i=2; i<=sqrt(x); i++)
        if(x%i==0)
        {
            res=res/i*(i-1);
            while(x%i==0)x/=i;
        }
    if(x>1)res=res/x*(x-1);
    return res;
}
int main()
{
    while(~scanf("%lld",&n))
    {
        ans=0;
        for(i=1; i<sqrt(n); i++)if(n%i==0)
                ans+=i*euler(n/i)+n/i*euler(i);
        if(i*i==n)ans+=i*euler(i);
        printf("%lld\n",ans);
    }
}

 欧拉降幂:

幂塔个数 

为了求解这个式子a^bmodc,我们可以怎么做?
暴力pow?快速幂?
很显然,当b大到一定程度时,利用pow或者快速幂这样的算法是无法在给定时间内求解的,这时我们引入欧拉降幂算法,这个算法的特点就是降低幂方的值而不影响最终结果,使我们解决问题的时间缩短。
结论:
给出欧拉降幂的公式:当符合第三种情况即模数与底数不互质且次幂大于等于\wp (p)时可用该公式将次幂降幂

  整除分块:

 对于一段连续的区间,n/i的值是不变的,那么对于这一段区间,我们就可以跳过,O(1)计算出这一段区间的值 例如:10/6==10/7==10/8==10/9==10/10都等于1,所以可以i从7-10就可以直接跳过,i=10/1+1,i=11跳过  公式:i=(x/(x/i))+1

 void init () {
    int ans=0;
    for(int l=1,r,len;l<=n;l=r+1) {
        r=n/(n/l),len=r-l+1;
        ans+=len*(n/l);
    }
}

求1-n中与x互质的数的个数:

对x进行质因子分解设x的质因子的个数为z,则时间复杂度为O(2^z *z)

vector<ll> pme;
ll count_prime(ll n,ll x){
    pme.clear();
    for(ll i=2;i<=sqrt(x);++i){
        if(x%i==0){
            pme.push_back(i);
            while(x%i==0) x/=i;
        }
    }
    if(x>1) pme.push_back(x);
    ll sum=0;
    for(int i=1;i<(1<<pme.size());++i){
        ll z=1,num=0;
        for(int j=0;j<pme.size();++j)
            if(i>>j&1) z*=pme[j],++num;
        if(num&1) sum+=n/z;
        else sum-=n/z;
    }
    return n-sum;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值