题解 【UVA12995 Farey Sequence】
算法:线性筛求欧拉函数,本来还想杜教筛
本文主要给刚学线性筛欧拉函数的萌新看。神仙勿喷QwQ
\(\large{\texttt{Meaning}}\)
给定一个 \(n\) ,求 \(F(n)\) :有多少组数对 \([a,b](0<a<b\le n)\) 其中 \(a,b\) 互质。
\(\large{\texttt{Solution}}\)
将 \(F(n)\) 中的数对归类,设 \(f(n)\) 为 \(b\) 为 \(n\) 的数对 \([a,b]\) 的个数,发现 \(f\) 和 \(\varphi\) (欧拉函数,即 \(\varphi(n)=\sum_{i=1}^{n} [ \gcd (n,i) ==1]\) )意义是相同的,那么即 \(F(n)=\sum^{n}_{i=1} \varphi(n)\) 。
然后可以用线性筛求出 \(\varphi\) ,再作一次前缀和,得到 \(F\) 数组,结束了。
还是说说怎么线性筛求欧拉函数吧。
首先,我们有这么一个性质:
\(\varphi(n)=n*\prod_{p|n} (p-1)/p ~~~(p\in \texttt{prime})\)
先设 \(f(n)=\prod_{p|n} (p-1)/p ~~~(p\in \texttt{prime})\)
若一个质数 \(p\) 整除 \(n\) ,则 \(f(pn)=f(n)\) ,因为 \(pn\) 和 \(n\) 用质因数的种类相同( \(p\) 不是一个新质因数)。
则有
若一个质数 \(p\) 不整除 \(n\) ,则 \(f(pn)=f(n)*(p-1)/p\) ,因为p是一个新的质因数。
则有
发现这些式子在线性筛里面可以使用(每个数只会被筛到一次),只需要添上几行代码,且不会增加复杂度。(具体操作参考代码)
\(\large{\texttt{Code}}\)
#include <iostream>
#include <cstdio>
using namespace std;
// #define PB push_back
// #define MP make_pair
// const int M=200010;
#define int long long
// #define us unsigned
// #define LL long long
const int N = 1000000;
// const int mod = 998244353;
int a, ans, prime[N + 10], phi[N + 10], top;
inline void init()//线性筛欧拉函数
{
phi[1] = 1;//phi[1]较特殊
for (int i = 2; i <= N; i++)
{
if (!phi[i])
{
prime[++top] = i;
phi[i] = i - 1;
}
for (int j = 1; j <= top && i * prime[j] <= N; j++)
{
if (i % prime[j] == 0)
{
phi[i * prime[j]] = phi[i] * prime[j];
break;
}
phi[i * prime[j]] = phi[i] * phi[prime[j]];
}
}
for (int i = 1; i <= N; i++)//前缀和
phi[i] += phi[i - 1];
}
signed main()
{
init();
// freopen("in","r",stdin);
while (~scanf("%lld", &a))
{
if (!a)
break;
printf("%lld\n", phi[a] - phi[1]);//注意phi[1]取不了。
}
return 0;
}