( ext{Problem})
( ext{Analysis})
区间筛积性函数,如 (varphi)
因为 (r-l le 10^6),所以这个问题就是非常经典的了
比较常见的技巧
(varphi(n)=nprod(1-frac 1 p))
([l,r]) 以内的数若不为素数分解质因数后最小的必然小于 (sqrt r)
用 (sqrt r) 以内的素数算贡献即可
顺便除掉素数,就可以找到 (sqrt r) 以外的素数
( ext{Code})
#include<cstdio>
#include<cmath>
#include<iostream>
using namespace std;
typedef long long LL;
const int N = 1e6 + 5;
const LL P = 666623333;
int tot;
LL l, r, prime[N], num[N], vis[N];
void getprime(int Mx)
{
vis[1] = 1;
for(int i = 2; i <= Mx; i++)
{
if (!vis[i]) prime[++tot] = i;
for(int j = 1; j <= tot && prime[j] * i <= Mx; j++)
{
vis[prime[j] * i] = 1;
if (i % prime[j] == 0) break;
}
}
}
LL solve()
{
for(int i = 1; i <= r - l + 1; i++) vis[i] = num[i] = l + i - 1;
for(int i = 1; i <= tot && prime[i] <= r; i++)
{
for(LL j = max(1LL, l / prime[i]); j * prime[i] <= r; j++)
if (j * prime[i] >= l)
{
vis[j * prime[i] - l + 1] = vis[j * prime[i] - l + 1] - vis[j * prime[i] - l + 1] / prime[i];
while (num[j * prime[i] - l + 1] % prime[i] == 0)
num[j * prime[i] - l + 1] /= prime[i];
}
}
for(int i = 1; i <= r - l + 1; i++)
if (num[i] > 1) vis[i] = vis[i] - vis[i] / num[i];
LL ans = 0;
for(int i = 1; i <= r - l + 1; i++) ans = (ans + (l + i - 1 - vis[i])) % P;
return ans;
}
int main()
{
scanf("%lld%lld", &l, &r);
getprime(sqrt(r) + 5);
printf("%lld
", solve());
}
( ext{Addition})
区间筛 (mu)
同样的有 (r-l le 10^6)
同理,利用积性函数的性质即可
inline void solve_u(ll l, ll r)
{
for(int i = 1; i <= r - l + 1; i++) mu[i] = 1, num[i] = i + l - 1;
for(int i = 1; i <= totp && prime[i] <= r; i++)
{
for(ll j = max(l / prime[i], 1ll); j * prime[i] <= r; j++)
if (j * prime[i] >= l)
{
if (j % prime[i] == 0) mu[j * prime[i] - l + 1] = 0;
else mu[j * prime[i] - l + 1] *= -1, num[j * prime[i] - l + 1] /= prime[i];
}
}
for(int j = 1; j <= r - l + 1; j++)
if (mu[j] != 0 && num[j] != 1) mu[j] *= -1;
}