签到题
题目背景
这是一道签到题!
建议做题之前仔细阅读数据范围!
题目描述
我们定义一个函数:qiandao(x)为小于等于x的数中与x不互质的数的个数。
这题作为签到题,给出l和r,要求求(sum_{i=l}^r qiandao(i)~mod~666623333)。
输入输出格式
输入格式
一行两个整数,l、r。
输出格式
一行一个整数表示答案。
输入输出样例
输入样例 #1
233 2333
输出样例 #1
1056499
输入样例 #2
2333333333 2333666666
输出样例 #2
153096296
说明
对于30%的数据,(l,rleq 10^3)。
对于60%的数据,(l,rleq 10^7)。
对于100%的数据,(1 leq l leq r leq 10^{12}),(r-l leq 10^6)。
分析
(1 leq l leq r leq 10^{12}),因此朴素质数筛肯定是过不了了。
但是我们能注意到:
(r-l leq 10^6)。
有 P1835 内味了,因此不难想到是筛出 (1 sim r - l) 中所有质数,然后进行处理。
然后再分析题面要我们求什么:(sum_{i=l}^r qiandao(i)~mod~666623333)
再来看qiandao函数的定义:
qiandao(x)为小于等于x的数中与x不互质的数的个数
那么很显然,(qiandao(x) = x - varphi(x))。
所以做法就是,枚举 (1 sim r - l) 中每个质数 (p),计算 (p) 对 (l sim r) 间某个数 (i) 的 (varphi(i)) 的贡献,最后求和即可。
代码:
代码
/*
* @Author: crab-in-the-northeast
* @Date: 2020-10-03 22:52:17
* @Last Modified by: crab-in-the-northeast
* @Last Modified time: 2020-10-04 00:04:43
*/
#include <iostream>
#include <cstdio>
const int maxn = 1000005;
const int mod = 666623333;
typedef long long ll;
bool isprime[maxn];
ll prime_num[maxn], cnt;
ll phi[maxn], last[maxn];
void prime(ll n) {
for (ll i = 2; i <= n; ++i)
isprime[i] = true;
isprime[1] = false;
for (ll i = 2; i <= n; ++i) {
if (isprime[i]) prime_num[++cnt] = i;
for (ll j = 1; j <= cnt && i * prime_num[j] <= n; ++j) {
isprime[i * prime_num[j]] = false;
if (i % prime_num[j] == 0) break;
}
}
}
int main() {
ll l, r;
std :: scanf("%lld %lld", &l, &r);
prime(maxn - 5);
for (ll i = l; i <= r; ++i) {
ll idx = i - l;
phi[idx] = last[idx] = i;
}
for (ll i = 1; i <= cnt && prime_num[i] * prime_num[i] <= r; ++i) {
ll p = prime_num[i];
for (ll j = l / p * p + ((l % p) ? p : 0); j <= r; j += p) {
ll idx = j - l;
phi[idx] /= p;
phi[idx] *= p - 1;
while (last[idx] % p == 0)
last[idx] /= p;
}
}
for (ll i = l; i <= r; ++i) {
ll idx = i - l;
if (last[idx] > 1) {
phi[idx] /= last[idx];
phi[idx] *= (last[idx] - 1);
}
}
ll ans = 0;
for (ll i = l; i <= r; ++i) {
ll idx = i - l;
ans = (ans + (i - phi[idx]) % mod) % mod;
}
std :: printf("%lld
", ans);
return 0;
}