Processing math: 100%

[BZOJ 3994] 约数个数和

题意

求下式的值:

ni=1mj=1d(ij)

其中 d(x) 为约数个数函数
n,m5×104,q5×104

题解

d(ij)=a|ib|j[ab]Ans=ijd(ij)=ija|ib|j[ij]=ija|ib|jk|a,k|bμ(k)=knkimkjnkiamkjbμ(k)=kμ(k)nkimkjnkiamkjb1=kμ(k)nkimkjnkimkj=kμ(k)nkimkjnkimkj=kμ(k)(nkinki)(mkjmkj)

这时我们可以认为 g(x)=xi=1xi, 而由于n,m炒鸡小于是可以数论分块+记忆化来求 g(x), 然后随便筛一筛 μ 的前缀和就行了

代码实现

#include <bits/stdc++.h>

const int MAXN=5e4+10;

int cnt;
int mu[MAXN];
int pr[MAXN];
bool npr[MAXN];
long long g[MAXN];

long long Calc(int);
void EulerSieve(int);

int main(){
	int T;
	scanf("%d",&T);
	EulerSieve(5e4);
	while(T--){
		int n,m;
		scanf("%d%d",&n,&m);
		if(n>m)
			std::swap(n,m);
		long long ans=0;
		for(int i=1,j;i<=n;i=j+1){
			j=std::min(n/(n/i),m/(m/i));
			ans+=(mu[j]-mu[i-1])*Calc(n/i)*Calc(m/i);
		}
		printf("%lld\n",ans);
	}
	return 0;
}

long long Calc(int x){
	if(g[x]!=0)
		return g[x];
	else{
		for(int i=1,j;i<=x;i=j+1){
			j=x/(x/i);
			g[x]+=(j-i+1)*(x/i);
		}
		return g[x];
	}
}

void EulerSieve(int n){
	npr[0]=npr[1]=true;
	mu[1]=1;
	for(int i=2;i<=n;i++){


		if(!npr[i]){
			pr[cnt++]=i;
			mu[i]=-1;
		}
		for(int j=0,t;j<cnt&&(t=i*pr[j])<=n;j++){
			npr[t]=true;
			if(i%pr[j])
				mu[t]=-mu[i];
			else{
				mu[t]=0;
				break;
			}
		}
	}
	for(int i=1;i<=n;i++)
		mu[i]+=mu[i-1];
}

posted @   rvalue  阅读(313)  评论(0编辑  收藏  举报
编辑推荐:
· 现代计算机视觉入门之:什么是视频
· 你所不知道的 C/C++ 宏知识
· 聊一聊 操作系统蓝屏 c0000102 的故障分析
· SQL Server 内存占用高分析
· .NET Core GC计划阶段(plan_phase)底层原理浅谈
阅读排行:
· 我干了两个月的大项目,开源了!
· 千万级的大表,如何做性能调优?
· 盘点!HelloGitHub 年度热门开源项目
· Phi小模型开发教程:用C#开发本地部署AI聊天工具,只需CPU,不需要GPU,3G内存就可以运行,
· 你所不知道的 C/C++ 宏知识——基于《C/C++ 宏编程的艺术》
本博客已经弃用, 是否跳转到新博客的该文章?
点击右上角即可分享
微信分享提示