【模板】杜教筛

杜教筛用来解决积性函数前缀和的问题。
复杂度为(O(n^frac{2}{3}))
适用情况:
已知函数(f),求(sum f)
存在(f*g=F),且(g,sum g,F,sum F)容易求出。

常用公式:
(mu*I=[n=1])
(varphi*I=id)

以求(sum mu)为例。

[mu*I=[n=1] \ sum_{i = 1}^{n}[i = 1] = 1 \ 1 = sum_{i = 1}^{n}[i = 1] ]

构造出所求函数(mu)

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

(t=i/d)

[1 = sum_{t = 1}^{n} sum_{d = 1}^{lfloor frac{n}{t} floor} mu(d) \ ]

(M(lfloor frac{n}{t} floor) = sumlimits_{d = 1}^{lfloor frac{n}{t} floor} mu(d))$

[1 = sum_{t = 1}^{n} M(lfloor frac{n}{t} floor) \ M(n) = 1 - sum_{t = 2}^{n} M(lfloor frac{n}{t} floor) ]

对于(i<10^7),可以预处理出(M(i))的值,存到数组里。
比较大的数可以通过数论分块递推求解。

模板题:51nod 1244 莫比乌斯函数之和

注意:

  • 空间限制
  • 计算(f(x))时,因为需要递归,不能把(ans)开成全局变量!

(code)

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#define MogeKo qwq
using namespace std;

const int maxn = 1e7+5;
const int mod = 999979;

long long a,b;
int prime[5000005],mu[maxn],M[maxn];
int head[mod],nxt[1000005];
int cnt,tot;
pair <long long,long long> num[1000005];
bool vis[maxn],flag;

void Prime() {
	M[1] = mu[1] = 1;
	for(int i = 2; i <= 10000000; i++) {
		if(!vis[i]) {
			mu[i] = -1;
			prime[++tot] = i;
		}
		for(int j = 1; j <= tot && i*prime[j] <= 10000000; j++) {
			vis[i*prime[j]] = true;
			if(i % prime[j] == 0) break;
			else mu[i*prime[j]] = -mu[i];
		}
		M[i] = M[i-1] + mu[i];
	}
}

void add(long long key,long long val) {
	int x = key % mod;
	num[++cnt] = make_pair(key,val);
	nxt[cnt] = head[x];
	head[x] = cnt;
}

long long query(long long key) {
	int x = key % mod;
	for(int i = head[x]; i; i = nxt[i])
		if(num[i].first == key) {
			flag = true;
			return num[i].second;
		}
	return 0;
}

long long f(long long x) {
	if(x <= 10000000) return M[x];
	flag = false;
	long long ans = query(x);
	if(flag) return ans;
	for(long long i = 2,r; i <= x; i = r+1) {
		r = x/(x/i);
		ans += (r-i+1) * f(x/i);
	}
	ans = 1 - ans;
	add(x,ans);
	return ans;
}

int main() {
	scanf("%lld%lld",&a,&b);
	Prime();
	printf("%lld",f(b)-f(a-1));
	return 0;
}
原文地址:https://www.cnblogs.com/mogeko/p/13335990.html