杜教筛

一.杜教筛

这有一些资料
2016年国家候选队论文任之洲积性函数求和的几种方法
还有几篇博客
博客1
博客2

1.一般形式

\(f(n)\)为一个数论函数,求

\[S(n)=\sum_{i=1}^{n}f(i) \]

其中\(n\leq10^{10}\)

分析:
直接求很困难,可以采用的一个方法是找出另外一个函数\(g(x)\)

\[f*g=\sum_{i=1}^{n}\sum_{j|i}f(i)g(\frac{i}{j})=\sum_{ij \leq n}f(i)g(j)=\sum_{i=1}^{n}g(i)\sum_{j=1}^{\left\lfloor \frac{n}{i} \right\rfloor}f(j) \]

\[=\sum_{i=1}^{n}g(i)S(\left\lfloor \frac{n}{i} \right\rfloor) \]

然后就可以得到一个关于\(S(n)\)的递推式

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

如果的\((f*g)(i)\)前缀和以及\(g(i)\)的前缀和都很快计算,那么就可以很快地计算\(S(n)\),直接计算时间复杂度\(O(n^{\frac{3}{4}})\),线性筛预处理前\(n^{\frac{2}{3}}\)项之后,时间复杂度为\(O(n^{\frac{2}{3}})\)

2.\(\mu\)

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

分析:

\(g=1\)因为 \(\mu*l=\varepsilon\),所以,就可以得到

\[S(n)=\varepsilon-\sum_{i=2}^{n}S(\left\lfloor \frac{n}{i} \right\rfloor) \]

\[S(n)=1-\sum_{i=2}^{n}S(\left\lfloor \frac{n}{i} \right\rfloor) \]

时间复杂度\(O(n^{\frac{2}{3}})\)

3.\(\varphi\)

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

\(g=1\)因为\(\varphi*1=id\),所以

\[S(n)=\frac{n*(n+1)}{2}-\sum_{i=2}^{n}S(\left\lfloor \frac{n}{i} \right\rfloor) \]

(二)习题

1.\(bzoj3944\)

bzoj3944

解析上面知识部分有

所以直接上代码,一定要注意,杜教筛的时候循环从2开始

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
typedef long long ll;
typedef double dd;
#define For(i,j,k) for (ll i=j;i<=k;++i)
#define Forr(i,j,k) for (ll i=j;i>=k;--i)
#define Set(a,p) memset(a,p,sizeof(a))
using namespace std;

template<typename T>bool chkmax(T& a,T b) {return a<b?a=b,1:0;}
template<typename T>bool chkmin(T& a,T b) {return a>b?a=b,1:0;}

const int maxn=2500000+100;
const ll maxx=2500000;
struct node {
	ll phi,miu;
};
ll N;
ll p[maxn],vis[maxn];
ll phi[maxn],miu[maxn];
map<ll,ll>Phi,Miu;

inline void read(ll &x) {
	x=0;
	ll p=1;
	char c=getchar();
	while (!isdigit(c)) {if (c=='-') p=-1; c=getchar();}
	while (isdigit(c)) {x=(x<<1)+(x<<3)+(c-'0'); c=getchar();}
	x*=p;
}

inline void init() {
	miu[1]=1; phi[1]=1;
	For (i,2,maxx) {
		if (!vis[i]) {
			p[++N]=i; miu[i]=-1; phi[i]=i-1;
		}
		For (j,1,N) {
			ll k=i*p[j];
			if (k>maxx) break;
			vis[k]=1;
			if (i%p[j]==0) {
				miu[k]=0; phi[k]=phi[i]*p[j];
				break;
			}
			else {
				miu[k]=-miu[i]; phi[k]=phi[i]*(p[j]-1);
			}
		}
	}
	For (i,1,maxx) {
		phi[i]=phi[i-1]+phi[i];
		miu[i]=miu[i-1]+miu[i];
	}
}

node solve(ll n) {
	if (n<=maxx) return (node){phi[n],miu[n]};
	if (Phi[n]) return (node){Phi[n],Miu[n]};
	ll ans1=n*(n+1)/2,ans2=1;
	for (ll i=2,nxt=1;i<=n;i=nxt+1) {
		node anss=solve(n/i);
		nxt=(n/(n/i));
		ans1-=(nxt-i+1)*anss.phi; ans2-=(nxt-i+1)*anss.miu;
	}
	Phi[n]=ans1; Miu[n]=ans2;
	return (node){ans1,ans2};
}

int main() {
	init();
	ll tt; read(tt);
	while (tt--) {
		ll n; read(n);
		node ans=solve(n);
		printf("%lld %lld\n",ans.phi,ans.miu);
	}
	return 0;
}

posted @ 2018-04-13 14:40  Wuweizheng  阅读(199)  评论(0编辑  收藏  举报