bzoj2820-GCD

题意

(Tle 10^4) 次询问 (n,m) ,求

[sum _{i=1}^nsum _{j=1}^m[gcd(i,j) ext { is prime}] ]

分析

这题还是很有趣的。设 (nle m)

[egin{aligned} sum _{i=1}^nsum_{j=1}^m[gcd(i,j) ext { is prime}]&=sum _{i=1}^nsum _{j=1}^msum _k [k ext { is prime}][gcd(i,j)=k] \ &=sum _{i=1}^nsum _{j=1}^msum _{k|i,k|j}[k ext { is prime}]sum _{d|frac{i}{k},d|frac{j}{k}}mu(d) \ &=sum _{d=1}^nmu (d)sum _{k=1}^n[k ext { is prime}]sum _{i=1}^{lfloorfrac{n}{k} floor}sum _{j=1}^{lfloorfrac{m}{k} floor}[d|i,d|j] \ &=sum _{d=1}^nmu (d)sum _{k=1}^n[k ext { is prime}]lfloorfrac{n}{kd} floor lfloorfrac{m}{kd} floor \ &=sum _{i=1}^nlfloorfrac{n}{i} floor lfloorfrac{m}{i} floorsum _{k|i,k ext { is prime}}mu(frac{i}{k}) end{aligned} ]

(f(x)=sum _{k|x,k ext {is prime }}mu (x/k)) ,我们有:

[ans=sum _{i=1}^nlfloorfrac{n}{i} floorlfloorfrac{m}{i} floor f(i) ]

(f(x)) 可以在线性筛的过程中顺便处理出来,求前缀和就可以做到每次询问 (O(sqrt n))

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long giant;
inline int read() {
	int x=0,f=1;
	char c=getchar_unlocked();
	for (;!isdigit(c);c=getchar_unlocked()) if (c=='-') f=-1;
	for (;isdigit(c);c=getchar_unlocked()) x=x*10+c-'0';
	return x*f;
}
const int maxn=1e7+1;
bool np[maxn];
int p[maxn],ps=0,mu[maxn],f[maxn];
int main() {
#ifndef ONLINE_JUDGE
	freopen("test.in","r",stdin);
#endif
	mu[1]=1,f[1]=0;
	for (int i=2;i<maxn;++i) {
		if (!np[i]) p[++ps]=i,mu[i]=-1,f[i]=1;
		for (int j=1,tmp;j<=ps && (tmp=i*p[j])<maxn;++j) {
			np[tmp]=true;
			if (i%p[j]) mu[tmp]=-mu[i],f[tmp]=mu[i]-f[i]; else {
				mu[tmp]=0;
				f[tmp]=mu[i];
				break;
			}
		}
	}
	for (int i=2;i<maxn;++i) f[i]+=f[i-1];
	int T=read();
	while (T--) {
		int n=read(),m=read();
		if (n>m) swap(n,m);
		giant ans=0;
		for (int i=1,j;i<=n;i=j+1) {
			j=min(n/(n/i),m/(m/i));
			ans+=(giant)(f[j]-f[i-1])*(n/i)*(m/i);
		}
		printf("%lld
",ans);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/owenyu/p/7326932.html