POJ2478 Farey Sequence

题目链接:POJ2478 Farey Sequence

题目翻译:

问题描述
对于一个大于1的整数n,存在这样一个分数集合F,(F_i = a/b), 其中(0<a<bleqslant n)并且GCD(a,b) = 1, 前几项分别为:

  1. (F_2) = {1/2}
  2. (F_3) = {1/3, 1/2, 2/3}
  3. (F_4) = {1/4, 1/3, 1/2, 2/3, 3/4}
  4. (F_5) = {1/5, 1/4, 1/3, 1/2, 2/3, 2/5, 3/4, 3/5, 4/5}
    你的任务是输入n,2(leqslant)n(leqslant) 10(^6),输出|F(_n)|(即F(_n)中的项数)

输入格式:
多组测试数据,每组一行一个数n,n = 0表示结束

输出格式:
对于每组测试数据,输出一行一个数表示答案

样例:见题面


问题分析:
题目本质就是求Euler函数前n项和,Euler函数(Phi)(n)表示小于n的正整数中有多少个与n互质。
由于输入较大,可以考虑预处理,线性求出Euler函数

#include <cstdio>
#include <iostream>
using namespace std;
int read() {
	int w = 1,res = 0;
	char ch = getchar();
	while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
	while(ch >= '0' && ch <= '9') res = res * 10 + ch - '0', ch = getchar();
	return w * res;
}
const int N = 1000050;
int phi[N], prime[N], tot, ans;
bool Mark[N];
void Euler_phi() {//线性求Euler函数
	phi[1] = 1;
	for(int i = 2; i <= N - 10; i ++) {
		if(!Mark[i]) {//如果没有被筛掉
			prime[++ tot] = i;//那么它就是下一个质数
			phi[i] = i - 1;   //当i为质数时,phi[i] = i - 1;
		}
		for(int j = 1; j <= tot; j ++) {
			if(i * prime[j] > N) break;
			Mark[i * prime[j]] = 1;    //确定i * prime[j]不是质数
			if(i % prime[j] == 0) {    //接着我们看prime[j]是否是i的约数
				phi[i * prime[j]] = phi[i] *prime[j];
				break;
			} else {
				phi[i * prime[j]] = phi[i] *(prime[j] - 1);
			}/这里的prime[j] - 1就是phi[prime[j]]
		}
	}
}
int main() {
	Euler_phi();//线性筛
	int n;
	while(n = read()) {
		long long ans = 0;
		for(int i = 2; i <= n; i ++)
			ans += phi[i];//一次求出答案
		printf("%lld
", ans);//然后输出
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Wuzhuoming-sirenboke/p/13623679.html