題目描述
給出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;
}