素数筛,欧拉算法题目总结

   所有题目链接

D题

   先补一道简单的题,观察规律发现结果是小于等于所给数字n的每一项欧拉和。

方法一:
#include<iostream>
#define Max 1000010
using namespace std; 
int phi[Max];  
void getphi() {
    phi[1] = 1;
    for(int i = 1; i < Max; i++)
        phi[i] = i;
    for(int i = 2; i < Max; i++)
        if(phi[i] == i)//如果i是质数 
            for(int j = i; j < Max; j += i) 
                phi[j] = (phi[j] / i) * (i-1);

}//欧拉打表
int main(){
    getphi();
    int x;
	while(1){
		int x;	
		long long cnt = 0; 
		cin >> x;
		if(x == 0)
			break;
		else{
			for(int i = 2; i <= x; i++)
				cnt += phi[i]; 
		}	
			cout << cnt << endl; 
	}


    return 0;
}

依次求欧拉数,最后累加

方法二:
#include <stdio.h>
#include <iostream>
using namespace std;
int oula[1000010];
int main()
{
	int n;
	for(int i=1;i<1000010;i++)
	{
		oula[i]=i;
	}
	for(int i=2;i<1000010;i++)
	{
		if(oula[i]==i)
		{
			for(int j=i;j<1000010;j+=i)
			{
				oula[j]=(oula[j]/i)*(i-1);
			}
		}
	}
	while(cin >> n&&n)
	{
		long long ans=0;
		for(int i=2;i<=n;i++)
		{
			ans+=oula[i];
		}
		cout << ans << endl;
	}
	
}

 

B题

//F[N]=∑gcd(i, N) 得 F(N)=∑pi*φ(N/pi)
//φ(N/pi)就是1~N中所有满足gcd(s,N)=pi的s的个数
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;

int getphi(int n) {
	int rea = n;
	for(int i=2; i*i<n; i++) {
		if(n%i == 0) {
			rea = rea - rea/i;
			do{
				n /= i;
			}while(n%i == 0);
		}
	}
	if(n > 1) {
		rea = rea - rea/n;
	}
	return rea;
}
int main()  {
	int n;
	ll ans;
	while(scanf("%d",&n)!=EOF) {
		ans = 0;
		for(int i=1; i*i<=n;i++) {
			if(n%i == 0) {
				ans += i*getphi(n/i);
				if(i*i!=n) //避免重复相加 eg.当n=9,3*getphi(3)会出现两次
					ans += (n/i)*getphi(i);
			}
		}
		cout << ans <<endl;	
	}
	return 0;
}

C题   题意很简单,可与B题做对比

 

#include<iostream>
#define ll long long
using namespace std;
int getphi(int n) {
	int rea = n;
	for(int i=2; i*i<=n; i++) {
		if(n%i == 0) {
			rea = rea - rea/i;
			do{
				n /= i;
			}while(n%i == 0);
		}
	}
	if(n>1)
		rea = rea-rea/n;
	return rea;
}
int main() {
	int T;
	cin >> T;
	while(T--) {
		int n,m;
		ll cnt=0;
		cin >> n >> m;
		for(int i =1; i*i<=n; i++) {
			if(n%i == 0) {
				if(i >= m) 
					cnt += getphi(n/i);  //注意跟B题区分,这里是统计个数所以不用乘i 
				if(i*i!=n && n/i>=m) 
					cnt += getphi(i);
			}
		}
		cout << cnt << endl;
	}
	return 0;
}

 

F题  可以参见小陈同学的博客https://blog.csdn.net/qq_44587145/article/details/96131006,解释的十分详细,赞一个~,注意和要B题进行对比

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

#define ll long long
const int maxn = 4e6+ 7;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
typedef pair<int, int> pis;

int phi[maxn];

void getPhi() {
    for (int i = 1; i < maxn; i ++) 
        phi[i] = i;
    for (int i = 2; i < maxn; i ++) 
        if(phi[i] == i) 
            for (int j = i; j < maxn; j += i) 
                phi[j] = (phi[j]/i) * (i-1);
}

ll getS(int x) {
    return 1ll * (x + 1) * x / 2;
}

int main() { 
    getPhi();
    int n;
    while(cin >> n && n) {
        ll ans = 0;
        for (int i = 2; i <= n; i ++) {
            ans += getS(n/i) * phi[i];
        }
        cout << ans << endl;
    }

    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值