问题描述

BZOJ2820

LG2257


题解

\(\sum\limits_{i=1}^{n}{\sum\limits_{j=1}^{m}{[gcd(i,j)==p]}}\) ,其中 \(p\)为质数,\(n<m\)

考虑不要求 \(gcd(i,j)\) 为质数时的做法:

可以转化为

\[\sum\limits_{g=1}^{n}{g \times \sum\limits_{i=1}^{\lfloor \frac{n}{g} \rfloor}{\sum\limits_{j=1}^{\lfloor \frac{m}{g} \rfloor}{[gcd(i,j)==1]}}}\]

根据狄利克雷卷积和莫比乌斯函数的性质,得

\[\sum\limits_{g=1}^{n}{g \times \sum\limits_{i=1}^{\lfloor \frac{n}{g} \rfloor}{\sum\limits_{j=1}^{\lfloor \frac{m}{g} \rfloor}{\sum\limits_{x|gcd(i,j)}{\mu(x)}}}}\]

转化为枚举倍数,得

\[\sum\limits_{g=1}^{n}{g \times \sum\limits_{x=1}^{\lfloor \frac{n}{g} \rfloor}{\sum\limits_{i=1}^{\lfloor \frac{n}{gx} \rfloor}{\sum\limits_{j=1}^{\lfloor \frac{m}{gx} \rfloor}{1}}}}\]

\[\sum\limits_{g=1}^{n}{g \times \sum\limits_{x=1}^{\lfloor \frac{n}{g} \rfloor}{\mu(x) \lfloor \frac{n}{gx} \rfloor \lfloor \frac{m}{gx} \rfloor}}\]

接下来考虑 \(g\) 要是质数怎么办

构造函数 \(f(x)\),\(f(x)=\begin{cases}1&x \in \mathbb{P}\\0&x \notin \mathbb{P}\end{cases}\),其中 \(\mathbb{P}\) 为质数集合。

\(D=gx\) ,则要求的就是

\[\sum\limits_{D=1}^{n}{\lfloor \frac{n}{D} \rfloor \lfloor \frac{m}{D} \rfloor \times \sum\limits_{g|D}{f(g)\mu(\frac{D}{g})}}\]

发现右边的 \(\sum\limits_{g|D}{f(g)\mu(\frac{D}{g})}\) 是狄利克雷卷积的形式。

\(h(x)=f*\mu\) ,则可以通过枚举倍数的时间,在 \(O(k \ln n)\) 的时间复杂度求出 \(h(x)\) ,其中 \(k\)\([1,n]\) 中质数个数,约等于 \(\frac{n}{\ln n}\) ,于是约等于 \(O(n)\)

得到最终答案式子为

\[\sum\limits_{D=1}^{n}{h(D)\lfloor \frac{n}{D} \rfloor \lfloor \frac{m}{D} \rfloor}\]


\(\mathrm{Code}\)

#include<bits/stdc++.h>
using namespace std;

const int maxn=10000000;

int p[maxn+7],pr[maxn+7],miu[maxn+7];
int h[maxn+7],T,tot;

long long s[maxn+7];

void preprocess(void){
    miu[1]=1;
    for(int i=2;i<=maxn;i++){
        if(!p[i]) p[i]=i,pr[++tot]=i,miu[i]=-1;
        for(int j=1;j<=tot;j++){
            if((long long)i*pr[j]>maxn||pr[j]>p[i]) break;
            p[i*pr[j]]=pr[j];
            if(i%pr[j]) miu[i*pr[j]]=-miu[i];
            else miu[i*pr[j]]=0;
        }
    }
    for(int i=1;i<=tot;i++){
        for(int j=1;(long long)pr[i]*j<=maxn;j++){
            h[pr[i]*j]+=miu[j];
        }
    }
    for(int i=1;i<=maxn;i++) s[i]=s[i-1]+(long long)h[i];
}

void Init(void){
    scanf("%d",&T);
}

long long calc(int x,int y){
    if(x>y) swap(x,y);
    long long res(0);
    for( int l=1,r;l<=x;l=r+1){
        r=min(x/(x/l),y/(y/l));
        res+=(long long)(s[r]-s[l-1])*(long long)(x/l)*(y/l);
    }
    return res;
}

void Work(void){
    preprocess();
    while(T--){
        int x,y;
        scanf("%d%d",&x,&y);
        printf("%lld\n",calc(x,y));
    }
}

signed main(){
    Init();
    Work();
}