2024-03-28

2024-03-28

!

晚上自习

YY的GCD

Problem
i[1,n],j[1,m]   m,n107T104 组询问,求 gcd(i,j) 是素数的 (i,j) 对数

Solution

ans=pprimesi=1nj=1m[gcd(i,j)=p]=pprimesi=1npj=1mp[gcd(i,j)=1]

莫比乌斯函数有一个小性质

dxμ(d)=[x=1]

[gcd(i,j)=1]=dgcd(i,j)μ(d)

ans=pprimesi=1npj=1mpdgcd(i,j)μ(d)

考虑改变求和顺序
先枚举 k=gcd(i,j),则 i,j 均是 k 的倍数

ans=pprimesk=1min(np,mp)dkμ(d)×npk×mpk

接下来(按照题解说的)是常见的变换方式
t=pk

ans=pprimesk=1min(np,mp)dkμ(d)×nt×mt=t=1min(n,m)nt×mtpprimes,ptμ(tp)

k 的约数不用再枚举的原因是:t 实际上枚举的是 pk的所有约数 的乘积,已经考虑过了

最后面的和式可以在线性筛的时候预处理
剩下的数论分块

时间复杂度 O(n+Tn)

Code

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

typedef long long ll;

const int N=1e7+100;

ll n,m;

int primes[N],cntp;
bool st[N];
int mu[N];
ll sm[N];

void init_mu(int mx) {
	mu[1]=1;
	for(int i=2;i<=mx;i++) {
		if(!st[i]) primes[++cntp]=i,mu[i]=-1;
		for(int j=1;i*primes[j]<=mx;j++) {
			st[i*primes[j]]=true;
			if(i%primes[j]==0) {
				mu[i*primes[j]]=0;
				break;
			}
			mu[i*primes[j]]=-mu[i]; 
		}
	}
	for(int j=1;j<=cntp;j++)
		for(int i=1;i*primes[j]<=mx;i++)
			sm[i*primes[j]]+=mu[i]*1ll;
	for(int i=1;i<=mx;i++) sm[i]+=sm[i-1];
}

int main() {
	init_mu(1e7+10);
	int T;
	scanf("%d",&T);
	while(T--) {
		scanf("%lld%lld",&n,&m);
		if(n>m) swap(n,m);
		ll lft=1,rgh,ans=0;
		while(lft<=n) {
			rgh=min(n,min(n/(n/lft),m/(m/lft)));
			ans+=(sm[rgh]-sm[lft-1])*(n/lft)*(m/lft);
			lft=rgh+1;
		}
		printf("%lld\n",ans); 
	}
	
	return 0;
} 

GCD SUM

做完前边几个题,这个就很简单了

不写解析了

完蛋还没写完但是要回去了

回宿舍交了,过了

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

typedef long long ll;

const int N=1e5+100;

int primes[N],cntp;
bool st[N];
ll mu[N],sm[N];

void init_mu(int mx) {
	mu[1]=1;
	for(int i=2;i<=mx;i++) {
		if(!st[i]) primes[++cntp]=i,mu[i]=-1;
		for(int j=1;i*primes[j]<=mx;j++) {
			st[i*primes[j]]=true;
			if(i%primes[j]==0) {
				mu[i*primes[j]]=0;
				break;
			}
			mu[i*primes[j]]=-mu[i];
		}
	}
	for(int i=1;i<=mx;i++) sm[i]=sm[i-1]+mu[i];
}

ll n;

int main() {
	scanf("%lld",&n);
	init_mu(n+10);
	ll ans=0;
	for(int g=1;g<=n;g++) {
		int m=n/g;
		int lft=1,rgh;
		ll res=0;
		while(lft<=m) {
			rgh=min(m,m/(m/lft));
			res+=(sm[rgh]-sm[lft-1])*(m/lft)*(m/lft); 
			lft=rgh+1;
		}
		ans+=g*res;
	}
	printf("%lld\n",ans);
	
	return 0;
}
posted @   OrangeStar*  阅读(9)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
点击右上角即可分享
微信分享提示