题解-UVA12995 【Farey Sequence】

(large{ exttt{UVA12995}})

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

本文主要给刚学线性筛欧拉函数的萌新看。神仙勿喷QwQ


(large{ exttt{Meaning}})

给定一个 (n) ,求 (F(n)) :有多少组数对 ([a,b](0<a<ble n)) 其中 (a,b) 互质。


(large{ exttt{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 ~~~(pin exttt{prime}))

先设 (f(n)=prod_{p|n} (p-1)/p ~~~(pin exttt{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{ exttt{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
", phi[a] - phi[1]);//注意phi[1]取不了。
  }
  return 0;
}

({Large exttt{My Blog}})

原文地址:https://www.cnblogs.com/RedreamMer/p/13378617.html