题链:
http://www.lydsy.com/JudgeOnline/problem.php?id=2820
题解:
莫比乌斯反演
先看看这个题:HDU 1695 GCD(本题简化版)
HDU 1695 GCD:求满足x∈(1~n)和y∈(1~m),且gcd(x,y)=k的(x,y)的对数。
而这个k是给定的。
可以由莫比乌斯反演得到:(详见●HDU 1695 GCD)
$ANS=\sum_{d=1}^{n}\mu(d)\times\lfloor\frac{n}{d}\rfloor\times\lfloor\frac{m}{d}\rfloor$
但是本题的k是所有的质数,额...
我们可以先枚举一个质数p,然后仿照上面的做法,可以得到:
$ANS=\sum_p \sum_{d=1}^{n}\mu(d)\times\lfloor\frac{n/p}{d}\rfloor\times\lfloor\frac{m/p}{d}\rfloor$
这个复杂度还无法满足本题的数据。
然后把上面的求和式做如下化简:
令$T=pd$,
那么:$ANS=\sum_{T=1}^{n}{(}{\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor} \sum_{p|T}\mu(\frac{T}{p}){)}$
如果可以预处理出$\sum_{p|T}\mu(\frac{T}{p})$的值,
那么上式就可以$O(n)$求出,
如果运用向下取整的特性进行分块计算,就可以达到$O(\sqrt{n})$的复杂度。
至于$\sum_{p|T}\mu(\frac{T}{p})$,有两种求法:
设$sum[T]=\sum_{p|T}\mu(\frac{T}{p})$
1.枚举每个质数p,然后把他的倍数$T=\lambda p的sum[T]+=\mu(\frac{T}{p})$
2.运用$\mu$是积性函数的性质,可以在线型筛时求出。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 10000050
using namespace std;
long long ANS;
int musum[MAXN],mu[MAXN];
void Prime_Sieve(){
static bool np[MAXN],dp[MAXN]; mu[1]=1;
static int prime[MAXN],pnt;
for(int i=2;i<=10000000;i++){
if(!np[i]) prime[++pnt]=i,dp[i]=1,mu[i]=-1,musum[i]=1;
for(int j=1;j<=pnt&&i<=10000000/prime[j];j++){
np[i*prime[j]]=1; dp[i*prime[j]]=dp[i]&&i%prime[j];
mu[i*prime[j]]=i%prime[j]?-mu[i]:0;
if(i%prime[j]==0) musum[i*prime[j]]=dp[i]?mu[i]:0;
else musum[i*prime[j]]=musum[i]*mu[prime[j]]+mu[i];
if(i%prime[j]==0) break;
}
}
for(int i=1;i<=10000000;i++) musum[i]+=musum[i-1];
}
int main(){
int n,m,Case,mini;
Prime_Sieve(); scanf("%d",&Case);
//while(scanf("%d",&n)) printf("%d\n",musum[n]);
while(Case--){
scanf("%d%d",&n,&m); mini=min(n,m); ANS=0;
for(int i=1,last;i<=mini;i=last+1){
last=min(n/(n/i),m/(m/i));
ANS+=1ll*(musum[last]-musum[i-1])*(n/i)*(m/i);
}
printf("%lld\n",ANS);
}
return 0;
}