杜教筛
P4213
杜教筛 \(O(n^{\frac{2}{3}})\) 求 \(\sum_{i=1}^{n} \phi(n)\) 与 \(\sum_{i=1}^{n} u(n)\),\(n \le 10^{9}\)
const int N = 2e6 + 5;
bool st[N];
int primes[N], tot, mu[N], phi[N];
ll s_mu[N], s_phi[N];
map<ll,ll> mp_smu, mp_sphi;
void sieve(int n){
mu[1] = phi[1] = 1;
for(int i = 2; i <= n; i ++){
if(!st[i]){
primes[++tot] = i;
mu[i] = -1;
phi[i] = i - 1;
}
for(int j = 1; j <= tot && i * primes[j] <= n; j ++){
st[i * primes[j]] = true;
if(i % primes[j] == 0){
phi[i * primes[j]] = phi[i] * primes[j];
break;
}
mu[i * primes[j]] = -mu[i];
phi[i * primes[j]] = phi[i] * (primes[j] - 1);
}
}
}
ll Sphi(ll n){
if(n <= (int)2e6) return s_phi[n];
if(mp_sphi.count(n)) return mp_sphi[n];
ll ans = n * (n + 1) / 2;
for(ll l = 2, r; l <= n; l = r + 1){
r = n / (n / l);
ans -= Sphi(n / l) * (r - l + 1);
}
return mp_sphi[n] = ans;
}
ll Smu(ll n){
if(n <= (int)2e6) return s_mu[n];
if(mp_smu.count(n)) return mp_smu[n];
ll ans = 1;
for(ll l = 2, r; l <= n; l = r + 1){
r = n / (n / l);
ans -= Smu(n / l) * (r - l + 1);
}
return mp_smu[n] = ans;
}
void solve()
{
int n;
cin >> n;
cout << Sphi(n) << " " << Smu(n) << '\n';
}
P3768
Q:给定 \(n,m\),求:
\[\sum_{i=1}^{n}\sum_{j=1}^{m} ij\gcd(i,j)
\]
\(n \le 10^{10}\)
const int N = 5e6 + 5;
bool st[N];
int primes[N], tot, mu[N], phi[N];
ll s_phi[N];
ll n;
int p;
void sieve(int n){
mu[1] = phi[1] = 1; // init
for(int i = 2; i <= n; i ++){
if(!st[i]){
primes[++tot] = i;
mu[i] = -1;
phi[i] = i - 1;
}
for(int j = 1; j <= tot && primes[j] <= n / i; j ++){
st[i * primes[j]] = true;
if(i % primes[j] == 0){ // i 是 primes[j] 的倍数
mu[i * primes[j]] = 0; // 质因子 primes[j] 至少有2个,mu 一定为 0
phi[i * primes[j]] = phi[i] * primes[j];
break;
}
// i 不是 primes[j] 的倍数时,i 与 primes[j] 互质,积性函数性质成立
mu[i * primes[j]] = -mu[i]; // 任意质数的 mu 均为 -1
phi[i * primes[j]] = phi[i] * (primes[j] - 1); // 任意质数 p 的 phi 均为 p - 1
}
}
for(int i = 1; i <= n; i ++){
s_phi[i] = (s_phi[i - 1] + 1ll * i * i % p * phi[i] % p) % p;
}
}
ll qpow(ll a, ll b, int p){
ll res = 1;
while(b){
if(b & 1) res = res * a % p;
b >>= 1;
a = a * a % p;
}
return res;
}
int inv6;
ll S2(ll x){
return LL(1) * x * (x + 1) % p * (2 * x + 1) % p * inv6 % p;
}
ll S3(ll x){
return (LL(1) * x * (x + 1) / 2) % p * (LL(1) * x * (x + 1) / 2) % p;
}
map<ll,ll> mp;
ll Sn(ll x){
if(x <= (int)5e6) return s_phi[x];
if(mp.count(x)) return mp[x];
ll res = S3(x);
for(ll l = 2, r; l <= x; l = r + 1){
r = x / (x / l);
res = (res - (S2(r) - S2(l - 1) + p) % p * Sn(x / l) % p + p) % p;
}
return mp[x] = res;
}
void solve()
{
cin >> p >> n;
sieve(5e6);
inv6 = qpow(6, p - 2, p);
ll ans = 0;
for(ll l = 1, r; l <= n; l = r + 1){
r = n / (n / l);
ans = (ans + (Sn(r) - Sn(l - 1) + p) % p * S3(n / l) % p) % p;
}
cout << ans << "\n";
}
复杂度分析:主函数内是整除分块套杜教筛。单次调用杜教筛的复杂度为 \(O(n^{\frac{2}{3}})\),整除分块调用 \(O(\sqrt n)\) 次,但是不能直接把二者相乘作为最终的复杂度,因为当 \(n\) 很小时,杜教筛可以直接返回已计算结果。很难精确地估算本题复杂度,但是能过qwq...



浙公网安备 33010602011771号