题解-UVA12995 【Farey Sequence】

\(\large{\texttt{UVA12995}}\)

算法:线性筛求欧拉函数,本来还想杜教筛

本文主要给刚学线性筛欧拉函数的萌新看。神仙勿喷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\) 不是一个新质因数)。

则有

\[\varphi(pn)=\varphi(n)*p \]

若一个质数 \(p\) 不整除 \(n\) ,则 \(f(pn)=f(n)*(p-1)/p\) ,因为p是一个新的质因数。

则有

\[\varphi(pn)=\varphi(n)*p*(p-1)/p= \varphi(n)*(p-1) \]

发现这些式子在线性筛里面可以使用(每个数只会被筛到一次),只需要添上几行代码,且不会增加复杂度。(具体操作参考代码)


\(\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;
}

\(\blue{\Large\texttt{My Blog}}\)

猜你喜欢

转载自www.cnblogs.com/RedreamMer/p/13378617.html