BZOJ 2820: YY的GCD


题目


2820: YY的GCD

Time Limit: 10 Sec  Memory Limit: 512 MB

Description

神犇YY虐完数论后给傻×kAc出了一题
给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对
kAc这种傻×必然不会了,于是向你来请教……
多组输入

Input

第一行一个整数T 表述数据组数
接下来T行,每行两个正整数,表示N, M

Output

T行,每行一个整数表示第i组数据的结果

Sample Input

2
10 10
100 100

Sample Output

30
2791

HINT

T = 10000

N, M <= 10000000


题解


这道题目是莫比乌斯反演,限预处理,然后计算答案。


【原谅我无耻盗图、12点了我要去吃饭了!!!!!】


代码


/*Author:WNJXYK*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
using namespace std;

#define LL long long
#define Inf 2147483647
#define InfL 10000000000LL

inline void swap(int &x,int &y){int tmp=x;x=y;y=tmp;}
inline void swap(LL &x,LL &y){LL tmp=x;x=y;y=tmp;}
inline int remin(int a,int b){if (a<b) return a;return b;}
inline int remax(int a,int b){if (a>b) return a;return b;}
inline LL remin(LL a,LL b){if (a<b) return a;return b;}
inline LL remax(LL a,LL b){if (a>b) return a;return b;}

const int Maxn=10000000;

/*
LL prime[Maxn/2+10];
bool valid[Maxn+10];
int primes;
inline void getPrime(){
	memset(valid,true,sizeof(valid));
	for (int i=2;i<=Maxn;i++){
		if (valid[i])prime[++primes]=i;
		for (int j=1;j<=primes && prime[j]*i<=Maxn;j++){
			valid[prime[j]*i]=false;
			if (i%prime[j]==0) break;
		}
	}
}


LL miu[Maxn+10];
inline void getMiu(){
	for (int i=1;i<=Maxn;i++){
		int target=(i==1?1:0);
		int delta=target-miu[i];
		miu[i]=delta;
		for (int j=i+i;j<=Maxn;j+=i) miu[j]+=delta;
	}
}

LL phi[Maxn+10];
LL minDiv[Maxn+10];
LL sum[Maxn+10];
inline void getPhi(){
	for (int i=1;i<=Maxn;i++) minDiv[i]=i;
	for (int i=2;i<=i*i;i++)
		if (minDiv[i]=i)
			for (int j=i*i;j<=Maxn;j+=i)
				minDiv[j]=i;
	phi[1]=1;
	for (int i=2;i<=Maxn;i++){
		phi[i]=phi[i/minDiv[i]];
		if ((i/minDiv[i])%minDiv[i]==0){
			phi[i]*=minDiv[i];
		}else{
			phi[i]*=minDiv[i]-1;
		}
	}
}
*/
int primes,prime[Maxn],mu[Maxn],g[Maxn],sum[Maxn];
void getPrime_Miu_G_S(){
    static bool vis[Maxn];
    memset(vis,0,sizeof(vis));
    mu[1]=1;primes=0;
    for(int i=2;i<Maxn;i++){
        if(!vis[i])
            prime[primes++]=i,mu[i]=-1,g[i]=1;
        for(int j=0;j<primes&&i*prime[j]<Maxn;j++){
            vis[i*prime[j]]=1;
            if(i%prime[j])
                mu[i*prime[j]]=-mu[i],g[i*prime[j]]=mu[i]-g[i];
            else{ 
				mu[i*prime[j]]=0;g[i*prime[j]]=mu[i];break;}
        }
    }
    sum[0]=0;
    for(int i=1;i<Maxn;i++)
        sum[i]=sum[i-1]+g[i];
}

int main(){
	getPrime_Miu_G_S();
	int T;
    scanf("%d",&T);
    while(T--){
        LL n,m;
        scanf("%lld%lld",&n,&m);
        if(n>m) swap(n,m);
        LL ans=0;
        for(int i=1,last;i<=n;i=last+1){
            last=min(n/(n/i),m/(m/i));
            ans+=(n/i)*(m/i)*(sum[last]-sum[i-1]);
        }
        printf("%lld
",ans);
    }
    return 0;
}



原文地址:https://www.cnblogs.com/WNJXYK/p/4063922.html