首页 > 其他分享 >杜教筛

杜教筛

时间:2022-09-22 19:11:35浏览次数:46  
标签:lfloor frac gcd sum rfloor 杜教 mu

没时间了,记几个公式好了。

令 \(S(n)=\sum_{i=1}^nf(i)\),则 \(g(1)S(n)=\sum_{i=1}^n(f*g)(i)-\sum_{i=\bm 2}^nS(\lfloor\frac ni\rfloor)\)。
e.g.
\(f=\mu,S(n)=\sum_{i=1}^n(\mu*1)(i)-\sum_{i=\bm 2}^nS(\lfloor\frac ni\rfloor)=1-\sum_{i=\bm 2}^nS(\lfloor\frac ni\rfloor)\);
\(f=\varphi,S(n)=\sum_{i=1}^n(\varphi*1)(i)-\sum_{i=\bm 2}^nS(\lfloor\frac ni\rfloor)={n(n+1)\over 2}-\sum_{i=\bm 2}^nS(\lfloor\frac ni\rfloor)\)。
递归调用即可。注意记忆化。

求 \(\sum \mu\):

unordered_map<int,int>bk,smu;
int Smu(int n){
	if(n<=1e6)return smu[n];
	if(bk[n])return smu[n];
	bk[n]=1;
	int ret=1;
	for(int i=2,j;i<=n;i=j+1){
		j=n/(n/i);
		ret-=(j-i+1)*Smu(n/i);
	}
	return smu[n]=ret;
}
//main
mu[1]=1;
for(int i=2;i<=1e6;i++){
	if(!v[i])mu[i]=-1,p[++n_p]=i;
	for(int j=1;j<=n_p&&p[j]*i<=1e6;j++){
		v[p[j]*i]=1;
		if(i%p[j])mu[i*p[j]]=-mu[i];
		else {mu[i*p[j]]=0;break;}
	}
}
	for(int i=1;i<=1e6;i++)smu[i]=smu[i-1]+mu[i];

复杂度是 \(O(n^{\frac34})\),通过预处理 \(S(1)\sim S(n^{\frac23})\) 可以做到 \(O(n^{\frac23})\)。证明需要使用高等数学。

【习题1】利用 \(S_1(n)=\sum_{i=1}^n\mu(i)\) 求 \(S_2(n)=\sum_{i=1}^n\varphi(i)\).
不难由莫比乌斯反演推得 \(S_2'(n)=\sum_{i=1}^n\sum_{j=1}^n[\gcd(i,j)=1]=\sum_{d=1}^n\mu(d)\lfloor\frac nd\rfloor^2\),而 \(S_2'(n)\) 就是除了 \((1,1)\),每个在 \(S_2(n)\) 中统计过的都统计了两次,所以 \(S_2(n)=(S_2'(n)+1)/2\)。求 \(S_2'(n)\) 可以直接整除分块并调用 Smu(),可证总复杂度不变。

int Sphi(int n){
	int ret=0;
	for(int i=1,j;i<=n;i=j+1){
		j=n/(n/i);
		ret+=(n/i)*(n/i)*(Smu(j)-Smu(i-1));
	}
	return (ret+1)/2;
}

【习题2】

【习题3】[NOI2016]循环之美
设无限循环小数 \(\frac xy\) 的循环节长度为 \(l\),根据循环小数的小数点右移 \(l\) 位不会导致小数部分的变化,可以列出

\[\frac{xk^l}y-\lfloor\frac{xk^l}y\rfloor=\frac{x}y-\lfloor\frac{x}y\rfloor \]

等式两边同时乘以 \(y\) 进行等价变形

\[xk^l-\lfloor\frac{xk^l}y\rfloor y=x-\lfloor\frac{x}y\rfloor y \]

等号左侧就是 \(xk^l\bmod y\) 的另一种形式,等式右侧同理,由此

\[xk^l\equiv x\pmod y \]

当且仅当 \(\gcd(x,y)=1\) 时,上式等价于 \(k^l\equiv 1\pmod y\)。而当且仅当 \(\gcd(k,y)=1\) 时,存在 \(l\) 使此式成立。
综上,只需要统计 \(\sum_{i=1}^n\sum_{j=1}^m[\gcd(i,j)=1][\gcd(j,k)=1]\)。

考察 \([\gcd(j,k)=1]\)

\[f(n,m,k)=\sum_{i=1}^n\sum_{j=1}^m[\gcd(i,j)=1][\gcd(j,k)=1]\\ =\sum_{i=1}^n\sum_{j=1}^m[\gcd(i,j)=1]\sum_{d|j,d|k}\mu(d)\\ =\sum_{d|k}\mu(d)\sum_{i=1}^n\sum_{d|j,j\le m}[\gcd(i,j)=1]\\ =\sum_{d|k}\mu(d)\sum_{i=1}^n\sum_{q=1}^{m/d}[\gcd(i,qd)=1]\\ =\sum_{d|k}\mu(d)\sum_{q=1}^{m/d}\sum_{i=1}^n[\gcd(i,q)=1][\gcd(i,d)=1]\\ =f(m/d,n,d)\]

从而可以递推。考虑到 \(d\le k\),\(m/d\) 也向着减小的方向发展,但 \(d\) 在 \(k=1\) 时就一直保持在 \(1\) 不变了,所以边界是:

  • \(f(n,0,k)=f(0,m,k)=0\)
  • \(f(n,m,1)=\sum_{d=1}^{\min(n,m)}\mu(d)\lfloor\frac nd\rfloor\lfloor\frac md\rfloor\)

后者直接整除分块计算,但是要用杜教筛处理 \(\sum \mu\)。
实际表现良好,高人证明复杂度为

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
int n,m,k,n_p,p[N],mu[N];
bool v[N];
unordered_map<int,int>bk,smu;
int Smu(int n){
	if(n<=1e6)return smu[n];
	if(bk[n])return smu[n];
	bk[n]=1;
	int ret=1;
	for(int i=2,j;i<=n;i=j+1){
		j=n/(n/i);
		ret-=(j-i+1)*Smu(n/i);
	}
	return smu[n]=ret;
}
int f(int n,int m,int k){
	if(!n||!m)return 0;
	if(k==1){
		int ret=0;
		for(int i=1,j;i<=min(n,m);i=j+1){
			j=min(n/(n/i),m/(m/i));
			ret+=(Smu(j)-Smu(i-1))*(n/i)*(m/i);
		}
		return ret;
	}
	int ret=0;
	for(int i=1;i*i<=k;i++)if(k%i==0){
		if(mu[i])ret+=mu[i]*f(m/i,n,i);
		if(i*i!=k&&mu[k/i])ret+=mu[k/i]*f(m/(k/i),n,k/i);
	}
	return ret;
}
signed main(){
	mu[1]=1;
	for(int i=2;i<=1e6;i++){
		if(!v[i])mu[i]=-1,p[++n_p]=i;
		for(int j=1;j<=n_p&&p[j]*i<=1e6;j++){
			v[p[j]*i]=1;
			if(i%p[j])mu[i*p[j]]=-mu[i];
			else {mu[i*p[j]]=0;break;}
		}
	}
	for(int i=1;i<=1e6;i++)smu[i]=smu[i-1]+mu[i];
	cin>>n>>m>>k;
	cout<<f(n,m,k);
}

标签:lfloor,frac,gcd,sum,rfloor,杜教,mu
From: https://www.cnblogs.com/impyl/p/16720218.html

相关文章

  • 【模板】杜教筛
    #include<stdio.h>#include<math.h>#include<map>#defineullunsignedlonglong#definelltlonglongint#defineuitunsignedintconstintN=5e6+10;int......