POJ2478 Farey Sequence
题目翻译:
问题描述
对于一个大于1的整数n,存在这样一个分数集合F,\(F_i = a/b\), 其中\(0<a<b\leqslant n\)并且GCD(a,b) = 1, 前几项分别为:
- \(F_2\) =
- \(F_3\) =
- \(F_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\n", ans);//然后输出
}
return 0;
}