bzoj2820 [bzoj2820]YY的GCD(线性素数筛+莫比乌斯反演)

求gcd(i,j)为质数的个数。即
pi=1nj=1mgcd(i,j)==p
首先我们可以像bzoj2301一样把后一部分化简,得到(假定n< m)
pd=1n/pμ(d)n/pdm/pd
设k=pd,则得到
k=1np|kμ(k/p)n/km/k
我们预处理出前半部分的前缀和(利用线性素数筛),后面的就是用floor函数分块的套路算啦!素数是O(n/logn)级别的,更新时是均摊O(logn)的,因此预处理的复杂度是O(n)的。总的复杂度是 O(T(n))

#include 
using namespace std;
#define ll long long
#define N 10000010
int T,n,m,mu[N],prime[N],tot=0;
ll f[N];
bool notprime[N];
inline int read(){
    int x=0;char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x;
}
void Mobius(){
    memset(notprime,0,sizeof(notprime));
    mu[1]=1;notprime[1]=1;
    for(int i=2;i<=N;++i){
        if(!notprime[i]){
            prime[++tot]=i;mu[i]=-1;
        }
        for(int j=1;prime[j]*i<=N;++j){
            notprime[prime[j]*i]=1;
            if(i%prime[j]==0){
                mu[prime[j]*i]=0;break;
            }
            mu[prime[j]*i]=-mu[i];
        }
    }
    for(int j=1;j<=tot;++j)
        for(int i=1;prime[j]*i<=N;++i)
            f[prime[j]*i]+=mu[i];
    for(int i=2;i<=N;++i) f[i]+=f[i-1];
}
ll ANS(int a,int b){
    ll re=0;if(a>b) swap(a,b);
    int last;
    for(int i=1;i<=a;i=last+1){
        last=min(a/(a/i),b/(b/i));
        re+=(f[last]-f[i-1])*(a/i)*(b/i);
    }
    return re;
}
int main(){
//  freopen("a.in","r",stdin);
    Mobius();
    T=read();
    while(T--){
        n=read();m=read();
        printf("%lld\n",ANS(n,m));
    }
    return 0;
}

你可能感兴趣的:(bzoj,莫比乌斯反演)