前置知识
狄利克雷卷积
若      f(n)=i∣n∑g(i)h(in)
 则记      f=g∗h
杜教筛
假如要求某积性函数      f(n) 的前缀和      (n<1012)。
 假设另一个积性函数为      g(n),     h=f∗g,记      s(n)=i=1∑nf(i)
 则有      i=1∑nh(n)=i=1∑nj∣i∑g(j)f(ji)=j=1∑ng(j)i=1∑⌊jn⌋f(i)=j=1∑ng(j)s(⌊jn⌋)
 然后把      j=1 单独拎出来,有
       i=1∑nh(n)=g(1)s(n)+j=2∑ng(j)s(⌊jn⌋)
 那么      s(n)=g(1)i=1∑nh(n)−j=2∑ng(j)s(⌊jn⌋)
 如果      h(n) 可以快速求出来,我们就能很快求出      s(n)
下面举一些例子
求      i=1∑nφ(n) (n<1011)
 注意到      n=i∣n∑φ(i),也就是      Id=φ∗1
 那么我们让      h(n)=n,     g(n)=1
 代入上式中,那就有
      s(n)=2n∗(n+1)−j=2∑ns(⌊jn⌋)
 然后      n 枚举关键点      j,递归求      s(⌊jn⌋)
 复杂度大概是      O(n43)
 为了加速,我们可以先线性预处理      1e7 的前缀和
 这样递归只用递归大于      1e7 的关键点
 然后对于大于      1e7 的关键点,为了防止重复访问,我们采用记忆化,将      x 这个点的值存在      f[n/x] 里面。
 复杂度大概是      O(n32)
一道模板题
洛谷      p4213
 
代码如下
#include <bits/stdc++.h>
#define LL long long
#define N 3000005
using namespace std;
LL z = 1, sphi[N], t, smu[N], f[5005], g[5005];
int maxn = N - 5, cnt, n, p[N], x[N], mu[N], phi[N];
LL getphi(int x){
	int i, j;
	LL s = 0;
	unsigned l, r;
	if(x <= maxn) return sphi[x];
	if(f[n / x]) return f[n / x];
	for(l = 2; l <= x; l = r + 1){
		r = x / (x / l);
		s = s + (r - l + 1) * getphi(x / l);
	}
	f[n / x] = z * x * (x + 1) / 2 - s;
	return f[n / x];
}
LL getmu(int x){
	int i, j;
	LL s = 0;
	unsigned l, r;
	if(x <= maxn) return smu[x];
	if(g[n / x]) return g[n / x];
	for(l = 2; l <= x; l = r + 1){
		r = x / (x / l);
		s = s + (r - l + 1) * getmu(x / l);
	}
	g[n / x] = z - s;
	return g[n / x];
}
int main(){
	int i, j, T;
	mu[1] = phi[1] = 1;
	for(i = 2; i <= maxn; i++){
		if(!x[i]) x[i] = p[++cnt] = i, mu[i] = -1;
		for(j = 1; j <= cnt; j++){
			t = z * i * p[j];
			if(t > maxn) break;
			x[t] = p[j];
			if(i % p[j] == 0) break;
			mu[t] = -mu[i];
		}
	}
	for(i = 2; i <= maxn; i++){
		if(x[i / x[i]] == x[i]) phi[i] = phi[i / x[i]] * x[i];
		else phi[i] = phi[i / x[i]] * (x[i] - 1);
	}
	for(i = 1; i <= maxn; i++) sphi[i] = sphi[i - 1] + phi[i], smu[i] = smu[i - 1] + mu[i];
	scanf("%d", &T);
	while(T--){
		memset(f, 0, sizeof(f));
		memset(g, 0, sizeof(g));
		scanf("%d", &n);
		printf("%lld %lld\n", getphi(n), getmu(n));
	}
	return 0;
}

 京公网安备 11010502036488号
京公网安备 11010502036488号