2023/4/28 欧拉函数 线性筛 线性筛推欧拉函数模板

欧拉函数:给你一个数字p,表示1-p中与p互质的数的数量

求欧拉函数模板

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

利用线性筛去求快速求1-n每个数的欧拉函数模板

欧拉函数的一些性质:

当n与m互质时,\varphi(n*m)=\varphi(n)*\varphi(m)

 m时n*m的最小质因子,如果n是m的倍数时

则, \varphi(n*m)=\varphi(n)*m;

根据上面的性质则可以通过线性筛递推出1-n每个数字的欧拉函数

ll d1[N]={0},d2[N],d3[N]={0};
ll phi[N]={0};
void shai(ll n){
	int i,j,k=0;
	phi[1]=1;
	for(i=2;i<=n;i++){
		if(d1[i]==0){
			d2[++k]=i;
			phi[i]=i-1;
		}
		for(j=1;j<=k&&i*d2[j]<=n;j++){
			d1[i*d2[j]]=1;
			if(i%d2[j]==0){
				phi[i*d2[j]]=phi[i]*d2[j];break;
			}else{
				phi[i*d2[j]]=phi[i]*phi[d2[j]];
			}
		}
	}
}

题目:

P2568 GCD - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

对于一个gcd(a,b)=1,它等价于gcd(a*p,b*p)=p;

考虑每一个质数p对答案的贡献,求出(a,b)的范围

因该是max(a,b)*p<=n;

那么一个素数p的贡献因该是,小于等于n/p的所有的数字的欧拉函数的和*2(除了1)

通过线性筛处理出1-n所有的欧拉函数,再写一个前缀和数组即可做出本题

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using ull = unsigned long long;
const ll N = 2e7+10;


ll a[N]={0};
ll b[N]={0};
ll phi[N]={0};
vector<int>v;

void shai(ll n){
	int i,j,k=0;
	v.push_back(-1);
	phi[1]=1;
	for(i=2;i<=n;i++){
		if(a[i]==0){
			v.push_back(i);
			phi[i]=i-1;
		}
		k=v.size();
		for(j=1;j<k&&i*v[j]<=n;j++){
//			cout<<v[j]<<endl;
			a[i*v[j]]=1;
			if(i%v[j]==0){
				phi[i*v[j]]=phi[i]*v[j];
			}else{
				phi[i*v[j]]=phi[i]*phi[v[j]];
			}
		}
	}
}

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

void solve(){
	ll n,i,j,u,ans=0;
	cin>>n;
	shai(n);
	u=v.size();
	b[0]=0;
	for(i=1;i<=n;i++){
		if(i==1){
			b[i]=1;
			continue;
		}
		b[i]=b[i-1]+phi[i]*2;
	}
	for(i=1;i<u;i++){
		ans+=b[n/v[i]];
	}
	cout<<ans;
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	int t;
//	cin>>t;
	t=1;
	while(t--){
		solve();
	}			
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值