LG P4213【模板】杜教筛(Sum)

( ext{Problem})

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

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

(1 le n < 2^{31})

(Solution)

终于开始学杜教筛了!!!
求积性函数 (f) 的前缀和,杜教筛可以低于线性
考虑卷积,构造积性函数 (h = f * g)
然后套路地推出一个重要的结论

[g(1)S(n)=sum_{i=1}^n(f*g)(i)-sum_{i=2}^n S(lfloor frac n i floor) ]

这是一个递归式,快速计算这个式子
要能快速 (h) 的前缀和,最后的式子整出分块
提前筛出 (n^{frac 2 3}) 以内 (f) 的前缀和,算到直接使用
( ext{unordered_map}) 存下已经计算过的 (f) 的前缀和,进行记忆化

然后对于本题就是利用

[varphi * I = ID ]

[mu * I = epsilon ]

( ext{Code})

#include<cstdio>
#include<tr1/unordered_map>
#define LL long long
using namespace std;

tr1::unordered_map<int, LL> S_phi;
tr1::unordered_map<int, int> S_mu;

const int MAXN = 3e6;
int vis[MAXN + 5], mu[MAXN + 5], prime[MAXN], totp;
LL phi[MAXN + 5];
inline void sieve()
{
	vis[1] = mu[1] = phi[1] = 1;
	for(register int i = 2; i <= MAXN; i++)
	{
		if (!vis[i]) prime[++totp] = i, mu[i] = -1, phi[i] = i - 1;
		for(register int j = 1; j <= totp && prime[j] * i <= MAXN; j++)
		{
			vis[i * prime[j]] = 1;
			if (i % prime[j]) phi[i * prime[j]] = phi[i] * phi[prime[j]], mu[i * prime[j]] = -mu[i];
			else{phi[i * prime[j]] = phi[i] * prime[j]; break;}
		}
	}
	for(register int i = 1; i <= MAXN; i++) mu[i] += mu[i - 1], phi[i] += phi[i - 1];
}

LL Sum_phi(LL n)
{
	if (n <= MAXN) return phi[n];
	if (S_phi[n]) return S_phi[n];
	LL res = n * (n + 1) / 2, j;
	for(register LL i = 2; i <= n; i = j + 1)
	{
		j = n / (n / i);
		res -= (j - i + 1) * Sum_phi(n / i);
	}
	return S_phi[n] = res;
}
int Sum_mu(LL n)
{
	if (n <= MAXN) return mu[n];
	if (S_mu[n]) return S_mu[n];
	LL res = 1, j;
	for(register LL i = 2; i <= n; i = j + 1)
	{
		j = n / (n / i);
		res -= (j - i + 1) * Sum_mu(n / i);
	}
	return S_mu[n] = res;
}

int main()
{
	sieve();
	int T; scanf("%d", &T);
	for(; T; --T)
	{
		LL n; scanf("%lld", &n);
		printf("%lld %d
", Sum_phi(n), Sum_mu(n));
	}
}
原文地址:https://www.cnblogs.com/leiyuanze/p/15017652.html