/* 返回顶部 */

Luogu P2257 YY的GCD

gate
一年多前做的题,没想到当时还是会莫反的,果然现在越来越菜了

求:

\[\sum\limits_{i=1}^n\sum\limits_{j=1}^m[gcd(i,j)\in prime] \]

\(gcd(i,j)=k,n>m\)(否则swap)

\[\sum\limits_{k=1}^n\sum\limits_{i=1}^n\sum\limits_{j=1}^m[gcd(i,j)=k](k\in prime) \]

同时除以\(k\)

\[\sum\limits_{k=1}^n\sum\limits_{i=1}^{\lfloor \frac{n}{k}\rfloor}\sum\limits_{j=1}^{\lfloor \frac{m}{k}\rfloor}[gcd(i,j)=1](k\in prime) \]

因为

\[\begin{array} \ \because \sum\limits_{d∣n}\mu(d)=[n=1] \\ \therefore \sum\limits_{d∣gcd(i,j)}​μ(d) = [gcd(i,j)=1] \end{array} \]

所以可以把\([gcd(i,j)=1]\)替换掉,即

\[\sum\limits_{k=1}^n\sum\limits_{i=1}^{\lfloor \frac{n}{k}\rfloor}\sum\limits_{j=1}^{\lfloor \frac{m}{k}\rfloor}\sum\limits_{d|gcd(i,j)}\mu(d)(k\in prime) \]

\(d\)提前,同时把\(i,j\)除以\(d\)

\[\sum\limits_{k=1}^n\sum\limits_{d=1}^{\lfloor \frac{n}{k}\rfloor}\sum\limits_{i=1}^{\lfloor \frac{n}{kd}\rfloor}\sum\limits_{j=1}^{\lfloor \frac{m}{kd}\rfloor}\mu(d)(k\in prime) \]

发现后面两个可以变成整除分块

\[\sum\limits_{k=1}^n\sum\limits_{d=1}^{\lfloor \frac{n}{k}\rfloor}\mu(d)\lfloor \frac{n}{kd}\rfloor\lfloor \frac{m}{kd}\rfloor(k\in prime) \]

对于\(\lfloor \frac{n}{kd}\rfloor\)这种形式,可以进一步降低复杂度。
\(T=kd\)

\[\sum\limits_{k=1}^n\sum\limits_{d=1}^{\lfloor \frac{n}{k}\rfloor}\mu(d)\lfloor \frac{n}{T}\rfloor\lfloor \frac{m}{T}\rfloor(k\in prime) \]

\(d\)换成\(T\)

\[\sum\limits_{T=1}^n\sum\limits_{k|T}\mu(\frac{T}{k})\lfloor \frac{n}{T}\rfloor\lfloor \frac{m}{T}\rfloor(k\in prime) \]

调整一下位置

\[\sum\limits_{T=1}^n\lfloor \frac{n}{T}\rfloor\lfloor \frac{m}{T}\rfloor\sum\limits_{k|T}\mu(\frac{T}{k})(k\in prime) \]

发现,\(\sum\limits_{k|T}\)后面的部分可以预处理出来,
在枚举质数时,对于每个质数\(k\)的倍数\(T\)\(sum[T]+=\mu(\frac{T}{k})\)


代码如下

#include<iostream>
#include<cstdio>
#include<cstring>
#define MogeKo qwq
using namespace std;
const int maxn = 10000005;
int mu[maxn],prime[maxn],f[maxn],sum[maxn];
bool vis[maxn];
int t,n,m,cnt;
long long ans;

void Prime(){
	mu[1] = 1;
	for(int i = 2;i <= maxn-5;i++){
		if(!vis[i]){
			prime[++cnt] = i;
			mu[i] = -1;
		}
		for(int j = 1;j<=cnt && i*prime[j]<=maxn-5;j++){
			vis[i*prime[j]] = true;
			if(i%prime[j] == 0)break;
			mu[i*prime[j]] = -1*mu[i];
		}
	}
}

void Sum(){
	for(int j = 1;j <= cnt;j++)
		for(int i = 1;i*prime[j] <= maxn-5;i++)
			f[i*prime[j]] += mu[i];
	for(int i = 1;i <= maxn-5;i++)
		sum[i] = sum[i-1]+f[i];
}

int main(){
	scanf("%d",&t);
	Prime();
	Sum();
	while(t--){
		scanf("%d%d",&n,&m);
		ans = 0;
		for(int l = 1,r = 0;l <= min(n,m);l=r+1){
			r = min(n/(n/l),m/(m/l));
			ans += (long long)(n/l) * (m/l) * (sum[r]-sum[l-1]);
		}
		printf("%lld\n",ans);
	}
    return 0;
}
posted @ 2020-03-25 21:53  Mogeko  阅读(119)  评论(0编辑  收藏  举报