题目链接http://www.51nod.com/Challenge/Problem.html#!#problemId=1192
有一个M * N的表格,行与列分别是1 - M和1 - N,格子中间写着行与列的最大公约数Gcd(i, j)(1 <= i <= M, 1 <= j <= N)。
例如:M = 5, n = 4。
1 2 3 4 5
1 1 1 1 1 1
2 1 2 1 2 1
3 1 1 3 1 1
4 1 2 1 4 1
给出M和N,求这张表中有多少个质数。
输入
第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 1000) 第2 - T + 1行:每行2个数M,N,中间用空格分隔,表示表格的宽和高。(1 <= M, N <= 5 * 10^6)
输出
共T行,每行1个数,表示表格中质数的数量。
输入样例
2 10 10 100 100
输出样例
30 2791
对于一些函数f(n),如果我们很难直接求出它的值,而容易求出倍数和或约数和F(n),那么我们可以通过莫比乌斯反演来求得f(n)的值
本题:f(n)表示某一范围内gcd(x,y)=n的数对的数量,F(n)表示某一范围内n|gcd(x,y)的数对的数量
那么直接求f(n)并不是很好求,而F(n)求起来相对无脑一些,我们可以通过对F(n)进行莫比乌斯反演来求得f(n)
本题实际上就是求
常见套路,枚举gcd???
设
则
设
即
所以
易知
所以
所以
然后预处理+分块就OK了
(第一次做莫比乌斯反演,推理可能很迷很乱,可能还不对,(╥╯^╰╥))
莫比乌斯反演+分块 学习 https://blog.csdn.net/jerry99s/article/details/81867641
大佬的博客https://blog.csdn.net/coldfresh/article/details/78300865
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e6+5;
bool book[N];
int prime[N],cnt=0;
short int miu[N];
ll sum[N];
void init(){
miu[1]=1;//积性函数性质,不能漏
for(int i=2;i<N;i++){
if(!book[i]){
prime[cnt++]=i;
miu[i]=-1;
}
for(int j=0;j<cnt;j++){
ll t=(ll)i*prime[j];
if(t>=N) break;
book[t]=true;
if(i%prime[j]==0) break;
miu[t]=-miu[i];
}
}
for(int i=0;i<cnt;i++){
int k=N/prime[i];
for(int j=1;j<=k;j++){
sum[prime[i]*j]+=miu[j];
}
}
for(int i=1;i<N;i++){
sum[i]+=sum[i-1];
}
}
int main(){
init();
int T;
scanf("%d",&T);
while(T--){
int n,m;
scanf("%d%d",&n,&m);
ll ans=0;
if(n>m) swap(n,m);
for(int l=1,r;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
ans+=(ll)(n/l)*(m/l)*(sum[r]-sum[l-1]);
}
printf("%lld\n",ans);
}
return 0;
}