【数论】[素数筛,phi]P3601签到题

题目描述

给出l,r,要求求出\(\sum_{i = l}^r (i - phi[i]) mod 666623333\)

\(1\leq l\leq r\leq 10^{12}\)\(r - l \leq 10^6\)

Solution

对于一个数n,肯定有至少一个小于等于$\sqrt n $的(质)因子。因为 \(r \leq 10^{12}\),所以可以先预处理\(10^{6}\)以内的素数, 然后利用r - l比较小的条件,一个一个数筛一遍就是了。用每个质因子去筛l - r之间的数,同时求出每个数的phi。对于个别的大于\(\sqrt n\)的因子,最后特判就行了。

\(\phi (x) = n (1 - \frac {1}{p1})(1 - \frac {1}{p2})...(1 - \frac {1}{pk})\)

Code

#include <iostream>
#include <cstdio>
using namespace std;
inline long long read() {
  long long x = 0; int f = 0; char c = getchar();
  while (c < '0' || c > '9') f |= c == '-', c = getchar();
  while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
  return f? -x:x;
}

const int mod = 666623333;
long long l, r, ans;
int pri[1000006], cnt;
long long k[1000006], phi[1000006];//k记录原来的数
bool b[1000006];
inline void get_pri() {
  for (int i = 2; i <= 1000; ++i)
    if (!b[i]) for(int j = i << 1; j <= 1000000; j += i) b[j] = 1;
  for (int i = 2; i <= 1000000; ++i)
    if (!b[i]) pri[++cnt] = i;
}
int main() {
  get_pri();
  l = read(); r = read();
  for (long long i = l; i <= r; ++i) phi[i - l] = k[i - l] = i;//初始化
  for (int i = 1; i <= cnt; ++i)
    for (long long p = pri[i], j = max(2ll, (l - 1) / p + 1) * p; j <= r; j += p) {
                               //找一个最小的开始筛的数,手推一下
      long long x = j - l;
      phi[x] = phi[x] / p * (p - 1);//计算phi
      while (k[x] % p == 0) k[x] /= p;//为后面判断是否有大因子最铺垫
    }
  for (long long i = l; i <= r; (ans += i - phi[i - l]) %= mod, ++i)//写的有点非人类hhh
    if (k[i - l] != 1) phi[i - l] = phi[i - l] / k[i - l] * (k[i - l] - 1);
    //特判
  printf("%lld\n", ans);
  return 0;
}
posted @ 2019-10-08 15:01  Kylin_Seven  阅读(241)  评论(0编辑  收藏  举报