P2257 YY的GCD(莫比乌斯反演)

第一次做莫比乌斯反演,推式子真是快乐的很啊(棒读)

前置

若函数\(F(n)\)\(f(d)\)存在以下关系

\[ F(n)=\sum_{n|d}f(d) \]

则可以推出

\[ f(n)=\sum_{n|d}\mu(\frac{d}{n})F(d) \]

这就是莫比乌斯反演

题目要求

\(gcd(a,b)=\{prime\},a\in\left[1,n\right],b\in\left[1,m\right]\)

思路

根据题意所以设出\(f(n)\)表示\(gcd(a,b)=n\)\(a,b\)对数
根据莫比乌斯反演的形式

\[ F(n)=\sum_{n|d}f(d) \]

可以设出一个函数\(F(n)\),表示\(n|gcd(a,b)\)\((a,b)\)对数
因为\(n|gcd(a,b)\),所以\(a=k_1\times n,b=k_2\times n\)
所以显然有

\[ F(x)=\lfloor\frac{n}{x}\rfloor\times\lfloor\frac{m}{x}\rfloor \]

因为

\[ f(x)=\sum_{x|d}\mu(\frac{d}{x})F(d) \]

所以

\[ f(x)=\sum_{x|d}\mu(\frac{d}{x})\times\lfloor\frac{n}{d}\rfloor\times\lfloor\frac{m}{d}\rfloor \]

考虑到\(\frac{d}{n}\)的形式并不优美,我们换一种东西枚举

\[ f(x)=\sum_{t=1}^{\lfloor\frac{n}{x}\rfloor}\mu(t)\times\lfloor\frac{n}{t\times x}\rfloor\times\lfloor\frac{m}{t\times x}\rfloor \]

所以

\[ ans=\sum_{x\in\{prime\}}^nf(x)=\sum_{x\in\{prime\}}^n\sum_{t=1}^{\lfloor\frac{n}{x}\rfloor}\mu(t)\times\lfloor\frac{n}{t\times x}\rfloor\times\lfloor\frac{m}{t\times x}\rfloor \]

这样能拿到50PTS
然后设\(T=t*x\),这样形式就变得更优美了一些
原式变形为

\[ ans=\sum_{x\in\{prime\}}^nf(x)=\sum_{x\in\{prime\}}^n\sum_{t=1}^{\lfloor\frac{n}{x}\rfloor}\mu(\frac{T}{x})\times\lfloor\frac{n}{T}\rfloor\times\lfloor\frac{m}{T}\rfloor \]

\[ ans=\sum_{x\in\{prime\}}^nf(x)=\sum_{T=1}^{min(n,m)}\sum_{d\in\{prime\},d|T}\mu(\frac{T}{d})\times\lfloor\frac{n}{T}\rfloor\times\lfloor\frac{m}{T}\rfloor \]

\[ ans=\sum_{x\in\{prime\}}^nf(x)=\sum_{T=1}^{min(n,m)}\lfloor\frac{n}{T}\rfloor\times\lfloor\frac{m}{T}\rfloor\times\sum_{d\in\{prime\},d|T}\mu(\frac{T}{d}) \]

后面\(\mu\)的部分可以前缀和一下
前面的可以整除分块
加上线性筛
然后没了

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
short mu[10001000];
int n,m,T,iprime[10001000],cnt,isprime[10001000],summu[10001000];
void prime(int n){
    mu[1]=1;
    isprime[1]=true;
    for(int i=2;i<=n;i++){
        if(!isprime[i])
            iprime[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt&&iprime[j]*i<=n;j++){
            isprime[iprime[j]*i]=true;
            if(i%iprime[j]==0){
                mu[iprime[j]*i]=0;
                break;
            }
            mu[iprime[j]*i]=-mu[i];
        }
    }
    for(int i=1;i<=cnt;i++)
        for(int j=1;j*iprime[i]<=n;j++)
            summu[iprime[i]*j]+=mu[j];
    for(int i=1;i<=n;i++)
        summu[i]+=summu[i-1];
}
long long f(int n,int m){
    long long ans=0;
    for(int l=1,r;l<=min(n,m);l=r+1){
        r=min(n/(n/l),m/(m/l));
        ans+=1LL*(summu[r]-summu[l-1])*(n/l)*(m/l);
    }
    return ans;
}
int main(){
    prime(10000100);
    scanf("%d",&T);
    while(T--){
        long long ans=0;
        scanf("%d %d",&n,&m);
        if(n<m)
            swap(n,m);
        ans+=f(n,m);
        printf("%lld\n",ans);
    }
    return 0;
}
posted @ 2018-12-04 18:04  dreagonm  阅读(135)  评论(0编辑  收藏  举报