【莫比乌斯反演】[SDOI2015]约数个数和

原题链接

P3327 [SDOI2015]约数个数和

题目大意

求:

∑ i = 1 n ∑ j = 1 n d ( i × j ) \large\sum\limits_{i=1}^n\sum\limits_{j=1}^nd(i\times j) i=1nj=1nd(i×j)

其中 d ( i × j ) d(i\times j) d(i×j) 表示 i × j i\times j i×j 的因数个数。

题解

首先证明公式:

d ( i j ) = ∑ x ∣ i ∑ y ∣ j [ gcd ⁡ ( x , y ) = 1 ] \large d(ij)=\sum\limits_{x\mid i}\sum\limits_{y\mid j}[\gcd(x,y)=1] d(ij)=xiyj[gcd(x,y)=1]

证:

我们先考虑 i = p k 1 , j = p k 2 i=p^{k_1},j=p^{k_2} i=pk1,j=pk2,其中 p p p 是质数,现在我们要统计 i j ij ij 有多少种不同的因子,那么我们先考虑 x = 1 x=1 x=1,继续枚举 y y y,发现在 j j j 中可以一直选到 p k 2 p^{k_2} pk2 而做到不重不漏,其中得到的这一堆值分别是 1 , p , p 2 , … , p k 2 1,p,p^2,\ldots,p^{k_2} 1,p,p2,,pk2

接下来我不能再继续选取上述的因子,考虑怎么选出 p k 2 + 1 p^{k_2+1} pk2+1 这个因子,显然我只需要让 x = 1 x=1 x=1 变成 x = p x=p x=p,此时我们发现对于 x = p x=p x=p,我们已经不能再继续选取 y = p 0 , … , k 2 y=p^{0,\ldots,k_2} y=p0,,k2,因为已经被 x = 1 x=1 x=1 选过了,所以 x = p x=p x=p 的贡献是 1 1 1。同理此时我们已经选出了 p k 2 + i p^{k_2+i} pk2+i 这个因子,那我们只有令 x = p i + 1 , y = p k 2 x=p^{i+1},y=p^{k_2} x=pi+1,y=pk2 才能得到 p k 2 + i + 1 p^{k_2+i+1} pk2+i+1 这个因子。

所以简而言之,在这种情况下,我们总共能选取的因子个数是 k 2 + k 1 − 1 k_2+k_1-1 k2+k11。此时我们还可以发现,当我们考虑 x ≠ 1 x\neq 1 x=1 时,由于我们永远选取了 y = p k 2 y=p^{k_2} y=pk2,所以我们每个 x x x 只能贡献一次,这一次我不一定是 y = p k 2 y=p^{k_2} y=pk2,如果我们假定 y = 1 y=1 y=1,那么 x ≠ 1 x\neq 1 x=1 的贡献仍然是一次,相当于我们令这个 y = p k 2 y=p^{k_2} y=pk2 的贡献转移给了 y = 1 y=1 y=1。这个时候我们发现我们所有的贡献都来自于 x , y x,y x,y 中至少取了一个 1 1 1。也就是 gcd ⁡ ( x , y ) = 1 \gcd(x,y)=1 gcd(x,y)=1 的全部情况。

接下来推广到 i = ∏ p i k i , j = ∏ p j k j i=\prod p_i^{k_i},j=\prod p_j^{k_j} i=piki,j=pjkj。考虑我们在 i i i 中选出了 x = 1 x=1 x=1,此时 y y y 可以取到任何值,且最多只能取到 j j j。此时如果我们想要取到 p x j p_xj pxj,就必须依赖 i i i 中的 p x p_x px,而且这个 p x p_x px 不能与任何 y < j y<j y<j y y y 结合,因为已经被 x = 1 x=1 x=1 考虑过了。所以每一个 x ≠ 1 x\neq 1 x=1 都只会贡献一次 y = j y=j y=j,接下来我们不让 y = j y=j y=j 产生贡献,转移到 y = 1 y=1 y=1 x ≠ 1 x\neq 1 x=1 产生贡献。因此发现 x , y x,y x,y 中总是至少选取了一个 1 1 1,故 ∑ x ∣ i ∑ y ∣ j [ gcd ⁡ ( x , y ) = 1 ] = d ( i j ) \sum\limits_{x\mid i}\sum\limits_{y\mid j}[\gcd(x,y)=1]=d(ij) xiyj[gcd(x,y)=1]=d(ij)

举个例子方便理解,令 i = 2 3 , j = 2 5 i=2^3,j=2^5 i=23,j=25。我们先考虑 x = 1 x=1 x=1 的情况,此时 y y y 可以是 1 , 2 , 4 , 8 , 16 , 32 1,2,4,8,16,32 1,2,4,8,16,32 i j ij ij 中肯定有 64 64 64 这个因子,只靠 x = 1 x=1 x=1 是枚举不出来的,所以我们将 x = 1 x=1 x=1 改为 x = 2 x=2 x=2,这个时候 y = 1 , 2 , 4 , 8 , 16 y=1,2,4,8,16 y=1,2,4,8,16 的情况都会与 x = 1 x=1 x=1 的情况重合,所以我们不能考虑这些 y y y,因此只有 y = 32 y=32 y=32 的时候我们取到了我们以前没有取到的数 64 64 64。因此对于 x ≠ 1 x\neq 1 x=1,都只有 y = 32 y=32 y=32 产生了贡献,这不方便计算,产生了一次贡献可以视作是 y = 1 y=1 y=1 的贡献,尽管乘起来不是原来没有的因子,但反正我产生了一次贡献,因此我至少会在 x , y x,y x,y 中取一个 1 1 1。对于推广的情况同理。

带入公式得到:

∑ i = 1 n ∑ j = 1 m ∑ x ∣ i ∑ y ∣ j [ gcd ⁡ ( x , y ) = 1 ] \large\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sum\limits_{x\mid i}\sum\limits_{y\mid j}[\gcd(x,y)=1] i=1nj=1mxiyj[gcd(x,y)=1]

转化 [ n = 1 ] [n=1] [n=1] 的式子:

∑ i = 1 n ∑ j = 1 m ∑ x ∣ i ∑ y ∣ j ∑ d ∣ gcd ⁡ ( x , y ) μ ( d ) \large\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sum\limits_{x\mid i}\sum\limits_{y\mid j}\sum\limits_{d\mid \gcd(x,y)}\mu(d) i=1nj=1mxiyjdgcd(x,y)μ(d)

考虑先枚举 x , y x,y x,y

∑ x = 1 n ∑ y = 1 m ∑ i = 1 n ∑ j = 1 m [ x ∣ i    and    y ∣ j ] ∑ d ∣ gcd ⁡ ( x , y ) μ ( d ) \large\sum\limits_{x=1}^n\sum\limits_{y=1}^m\sum\limits_{i=1}^n\sum\limits_{j=1}^m[x\mid i\;\text{and}\;y\mid j]\sum\limits_{d\mid \gcd(x,y)}\mu(d) x=1ny=1mi=1nj=1m[xiandyj]dgcd(x,y)μ(d)

i = i ′ x , j = j ′ y i=i^\prime x,j=j^\prime y i=ix,j=jy,得:

∑ x = 1 n ∑ y = 1 m ∑ i = 1 ⌊ n x ⌋ ∑ j = 1 ⌊ m y ⌋ [ x ∣ i x    and    y ∣ j y ] ∑ d ∣ gcd ⁡ ( x , y ) μ ( d ) \large\sum\limits_{x=1}^n\sum\limits_{y=1}^m\sum\limits_{i=1}^{\lfloor\frac{n}{x}\rfloor}\sum\limits_{j=1}^{\lfloor\frac{m}{y}\rfloor}[x\mid ix\;\text{and}\;y\mid jy]\sum\limits_{d\mid \gcd(x,y)}\mu(d) x=1ny=1mi=1xnj=1ym[xixandyjy]dgcd(x,y)μ(d)

中括号内式子等于 1 1 1,我们直接省去:

∑ x = 1 n ∑ y = 1 m ∑ d ∣ gcd ⁡ ( x , y ) μ ( d ) ( ⌊ n x ⌋ ⌊ m y ⌋ ) \large\sum\limits_{x=1}^n\sum\limits_{y=1}^m\sum\limits_{d\mid \gcd(x,y)}\mu(d)\left(\left\lfloor\dfrac{n}{x}\right\rfloor\left\lfloor\dfrac{m}{y}\right\rfloor\right) x=1ny=1mdgcd(x,y)μ(d)(xnym)

继续拆掉 d ∣ gcd ⁡ ( x , y ) d\mid\gcd(x,y) dgcd(x,y)

∑ d = 1 n ∑ x = 1 n ∑ y = 1 m [ d ∣ x    and    d ∣ y ] μ ( d ) ( ⌊ n x ⌋ ⌊ m y ⌋ ) \large\sum\limits_{d=1}^n\sum\limits_{x=1}^n\sum\limits_{y=1}^m[d\mid x\;\text{and}\;d\mid y]\mu(d)\left(\left\lfloor\dfrac{n}{x}\right\rfloor\left\lfloor\dfrac{m}{y}\right\rfloor\right) d=1nx=1ny=1m[dxanddy]μ(d)(xnym)

x = x ′ d , y = y ′ d x=x^\prime d,y=y^\prime d x=xd,y=yd,得到:

∑ d = 1 n μ ( d ) ∑ x = 1 ⌊ n d ⌋ ∑ y = 1 ⌊ m d ⌋ ⌊ n x d ⌋ ⌊ m y d ⌋ \large\sum\limits_{d=1}^n\mu(d)\sum\limits_{x=1}^{\lfloor\frac{n}{d}\rfloor}\sum\limits_{y=1}^{\lfloor\frac{m}{d}\rfloor}\left\lfloor\dfrac{n}{xd}\right\rfloor\left\lfloor\dfrac{m}{yd}\right\rfloor d=1nμ(d)x=1dny=1dmxdnydm

接下来各回各家:

∑ d = 1 n μ ( d ) ∑ x = 1 ⌊ n d ⌋ ⌊ n x d ⌋ ∑ y = 1 ⌊ m d ⌋ ⌊ m y d ⌋ \large\sum\limits_{d=1}^n\mu(d)\sum\limits_{x=1}^{\lfloor\frac{n}{d}\rfloor}\left\lfloor\dfrac{n}{xd}\right\rfloor\sum\limits_{y=1}^{\lfloor\frac{m}{d}\rfloor}\left\lfloor\dfrac{m}{yd}\right\rfloor d=1nμ(d)x=1dnxdny=1dmydm

f ( n ) f(n) f(n) 表示 ∑ i = 1 n ⌊ n i ⌋ \sum\limits_{i=1}^n\left\lfloor\dfrac{n}{i}\right\rfloor i=1nin,得到:

∑ d = 1 n μ ( d ) f ( ⌊ n d ⌋ ) f ( ⌊ m d ⌋ ) \large\sum\limits_{d=1}^n\mu(d)f\left(\left\lfloor\dfrac{n}{d}\right\rfloor\right)f\left(\left\lfloor\dfrac{m}{d}\right\rfloor\right) d=1nμ(d)f(dn)f(dm)

内层的 f f f 函数可以整除分块解决,但为了不让每次询问都进行一次 O ( n ) \mathcal{O}(\sqrt{n}) O(n ) 的运算,我们提前算好这个前缀和。剩下的每次查询也是整除分块,提前预处理 μ ( d ) \mu(d) μ(d) 的前缀和即可,总时间复杂度 O ( T n ) \mathcal{O}(T\sqrt{n}) O(Tn )

代码

//P3327
//你 cnt=1 了吗?
#include<bits/stdc++.h>
#define int long long
#define mid ((l+r)>>1)
#define fir first
#define sec second
#define lowbit(i) (i&(-i))
using namespace std;
const int N=5e4+5;
const int inf=1e18;
struct edge{int to,nxt,l;};
inline int read(){
    char op=getchar();
    int w=0,s=1;
    while(op<'0'||op>'9'){
        if(op=='-') s=-1;
        op=getchar();
    }
    while(op>='0'&&op<='9'){
        w=(w<<1)+(w<<3)+op-'0';
        op=getchar();
    }
    return w*s;
}
//数论部分
const double pi=acos(-1);
const int mod=1e9+7;
int Mul(int a,int b){return (a%mod*b%mod)%mod;}
int Add(int a,int b){return (a+b)%mod;}
int Dec(int a,int b){return (a-b+mod)%mod;}
int Pow(int a,int k){
    int ans=1;
    while(k){
        if(k&1) ans=Mul(ans,a);
        a=Mul(a,a);
        k>>=1;
    }
    return ans;
}
int gcd(int x,int y){return y==0?x:gcd(y,x%y);}
int lcm(int x,int y){return x/gcd(x,y)*y;}
int inv(int x){return Pow(x,mod-2);}
void exgcd(int a,int b,int &x,int &y){
    if(b==0){
        x=1,y=0;
        return;
    }
    exgcd(b,a%b,x,y);
    int t=x;
    x=y;
    y=t-a/b*y;
}
int mu[N],vis[N],p[N],cnt=0,ans[N],sum[N];
void mobius(){
    mu[1]=1;
    for(register int i=2;i<=N-5;i++){
        if(!vis[i]){
            mu[i]=-1;
            p[++cnt]=i;
        }
        for(register int j=1;j<=cnt&&i*p[j]<=N-5;j++){
            vis[i*p[j]]=1;
            if(i%p[j]==0){
                mu[i*p[j]]=0;
                break;
            }
            mu[i*p[j]]=-mu[i];
        }
    }
    for(register int i=1;i<=N-5;i++) sum[i]=sum[i-1]+mu[i];
    for(register int i=1;i<=N-5;i++){//预处理整除分块
        for(register int l=1,r;l<=i;l=r+1){
            r=i/(i/l);
            ans[i]+=(i/l)*(r-l+1);
        }
    }
}
int Sqrt(int n,int m){
    int tot=0;
    for(register int l=1,r;l<=min(n,m);l=r+1){
        r=min(n/(n/l),m/(m/l));
        tot+=(sum[r]-sum[l-1])*ans[n/l]*ans[m/l];
    }
    return tot;
}
signed main(){
    int T=read();
    mobius();
    while(T--){
        int n=read(),m=read();
        printf("%lld\n",Sqrt(n,m));
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值