题目大意:定义\(qiandao(n)=\sum_{i=1}^{n}[gcd(i,n)\neq1]\),求\(\sum_{i=l}^rqiandao(i)\),其中\(l,r\leq 10^{12},r-l \leq 10^6\)
数论
分析:首先\(qiandao(n)=n-\varphi(n)\)
所以我们考虑咋把\(\sum_{i=l}^{r}\varphi(i)\)求出来
把\([l,r]\)内每个数利用唯一分解定理分解,由于一个数\(n\)分解后的指数之和不会超过\(log_2n\),所以我们只需要求出这个数有哪些质因子,然后暴力求\(\varphi\)即可
我们筛出\([1,\sqrt{10^{12}}=10^6]\)内的所有质数,对于每个质数,将它在\([l,r]\)内的所有倍数打上标记
根据神欧拉给出的结论,这个的时间复杂度是\(nlogn\)级别的
于是我们得到了\([l,r]\)内每个数\(x\),小于\(\sqrt{x}\)的质因子,将它们的幂次全部除掉,得到的数如果不是\(1\),那它一定是一个大于\(\sqrt{x}\)的质因子,我们得到了\(x\)的所有质因子
然后愉快的求\(\varphi\)即可
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 100,mod = 666623333;
inline ll add(ll a,ll b){return (a + b) % mod;}
bool vis[maxn];
vector<int> pri;
inline void sieve(){
for(int i = 2;i < maxn;i++){
if(!vis[i])pri.push_back(i);
for(int x : pri){
if(1ll * x * i >= maxn)break;
vis[i * x] = 1;
if(i % x == 0)break;
}
}
}
ll l,r,ans;
vector<int> vec[maxn];
int main(){
sieve();
cin >> l >> r;
for(int p : pri){
for(ll now = ceil((long double)l / p) * p;now <= r;now += p)
vec[now - l].push_back(p);
}
for(ll now = l;now <= r;now++){
ll tmp = now,phi = 1;
for(int p : vec[now - l]){
phi *= p - 1;
tmp /= p;
while((tmp % p) == 0){
phi *= p;
tmp /= p;
}
}
if(tmp != 1)phi *= tmp - 1;
ans = add(ans,now - phi);
}
cout << ans << '\n';
return 0;
}