杜教筛

link

用根号的时间求得一些特殊函数的前缀和。

要求 \(s_n=\sum\limits_{i=1}^nf_i\) ,然后不好求。而假如函数 \(g\) 和它俩的狄利克雷卷出来的 \(h\) 是好求的,那么可以推式子:

\[\sum\limits_{i=1}^nh_i=\sum\limits_{i=1}^n\sum\limits_{d|i} f(\frac{i}{d})g_d \]

\[\sum\limits_{i=1}^nh_i=\sum\limits_{d=1}^ng_d\sum\limits_{j=1}^{n/d}f_j \]

显然当 \(d=1\) 时右式会等于 \(s_n\)。把这东西拿出来:

\[\sum\limits_{i=1}^nh_i=g_1\times s_n+\sum\limits_{d=2}^ng_d\times s_{n/d} \]

\[s_n=\frac{\sum\limits_{i=1}^nh_i-\sum\limits_{d=2}^ng_d\times s_{n/d}}{g_1} \]

由于 \(g\) 的前缀和很好求,所以左上实际上可以用数论分块解决,然后再递归处理。这样一来复杂度就从 \(O(N)\) 降到了…… \(O(\sqrt{N}\log N)\)?(不会分析)。中间再做好记忆化即可。

然后具体问题具体分析,题目中希望求的是莫比乌斯函数和欧拉函数的前缀和,于是可以先线性筛出 \(10^6\) 个值方便后续计算。然后就是 \(g,h\) 函数的选择了。于是就有两个我不是很搞得懂的玄妙结论:

\[\mu*I=\varepsilon,\varphi*I=id \]

然后就可以啦。 \(\varepsilon\) 的前缀和是1, \(I\) 的前缀和是 \(n\)\(id\) 的前缀和是 \(\frac{n\times(n+1)}{2}\)

#include<bits/stdc++.h>
//#define feyn
#define int long long
using namespace std;
const int N=1000010;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
    wh*=f;return;
}

int ff[N],gg[N],p[N/2],cnt;
bool vis[N];
inline void init(){
	ff[1]=gg[1]=1;
	for(int i=2;i<N;i++){
		if(!vis[i])p[++cnt]=i,ff[i]=i-1,gg[i]=-1;
		for(int j=1;j<=cnt&&p[j]*i<N;j++){
			vis[i*p[j]]=true;
			if(i%p[j]==0){
				ff[i*p[j]]=ff[i]*p[j];break;
			}
			ff[i*p[j]]=ff[i]*(p[j]-1);
			gg[i*p[j]]=gg[i]*-1;
		}
	}
	for(int i=1;i<N;i++)ff[i]+=ff[i-1],gg[i]+=gg[i-1];
}
unordered_map<int,int>af;
inline int f(int wh){
	if(wh<N)return ff[wh];
	if(af[wh])return af[wh];
	int ans=wh*(wh+1)/2;
	for(int l=2,r;l<=wh;l=r+1){
		r=wh/(wh/l);
		ans-=(r-l+1)*f(wh/l);
	}
	return af[wh]=ans;
}
unordered_map<int,int>ag;
inline int g(int wh){
	if(wh<N)return gg[wh];
	if(ag[wh])return ag[wh];
	int ans=1;
	for(int l=2,r;l<=wh;l=r+1){
		r=wh/(wh/l);
		ans-=(r-l+1)*g(wh/l);
	}
	return ag[wh]=ans;
}

signed main(){
	
	#ifdef feyn
	freopen("in.txt","r",stdin);
	#endif
	
	init();
	int m,data;read(m);
	while(m--){
		read(data);
		printf("%lld %lld\n",f(data),g(data));
	}
	
	return 0;
}
posted @ 2022-08-08 14:33  Feyn618  阅读(16)  评论(0编辑  收藏  举报