[luogu p3601] 签到题
签到题
题目背景
这是一道签到题!
建议做题之前仔细阅读数据范围!
题目描述
我们定义一个函数: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,r\leq 10^3\)。
对于60%的数据,\(l,r\leq 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\n", ans);
return 0;
}