P4213 【模板】杜教筛

题目链接

\[ans_1=\sum_{i=1}^n\varphi(i) \]

\[ans_2=\sum_{i=1}^n \mu(i) \]

一眼杜教筛。

我们有:

  • \(\epsilon = 1 * \mu\)

  • \(\textrm{Id} = 1*\varphi\)

\(\epsilon\) 的前缀和为 \(1\)

\(\textrm{Id}\) 的前缀和为 \(\frac{n(n+1)}{2}\)

代码如下:

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N = 1e6+10;

int phi[N], mu[N], suphi[N], sumu[N], ans1, ans2;
bool notPrime[N];
vector<int>prime;
map<int, int>sudphi, sudmu;

int djsmu(int n){
	if(sudmu.count(n)) return sudmu[n];
	if(n <= 1e6) return sumu[n];
	int ans = 1;
	for(int l=2, r=0;l<=n;l=r+1){
		r = (n/(n/l));
		ans -= djsmu(n/l) * (r-l+1);
	}
	return sudmu[n] = ans;
}

int djsphi(int n){
	if(sudphi.count(n)) return sudphi[n];
	if(n <= 1e6) return suphi[n];
	int ans = (n*(n+1))/2;
	for(int l=2, r=0;l<=n;l=r+1){
		r = (n/(n/l));
		ans -= djsphi(n/l) * (r-l+1);
	}
	return sudphi[n] = ans;
}

void euler(int n){
	phi[1] = 1, mu[1] = 1;
	for(int i=2;i<=n;i++){
		if(!notPrime[i]){
			phi[i] = i-1;
			mu[i] = -1;
			prime.push_back(i);
		}
		for(auto p : prime){
			if(i*p > n) break;
			notPrime[i*p] = 1;
			if(i%p==0){
				phi[i*p] = p * phi[i];
				mu[i*p] = 0;
				break;
			}
			phi[i*p] = (p-1) * phi[i];
			mu[i*p] = -mu[i];
		}
	}
	for(int i=1;i<=n;i++){
		suphi[i] = suphi[i-1] + phi[i];
		sumu[i] = sumu[i-1] + mu[i];
	}
}

signed main(){
	euler(1e6);
	int T;cin>>T;
	while(T--){
		int x;cin>>x;
		cout<<djsphi(x)<<' '<<djsmu(x)<<'\n';
	}
}
posted @ 2025-07-12 11:04  fyv233  阅读(12)  评论(0)    收藏  举报