莫比乌斯反演

一.莫比乌斯函数:
1.定义:

μ ( d ) = { <mstyle displaystyle="false" scriptlevel="0"> 1 , </mstyle> <mstyle displaystyle="false" scriptlevel="0"> <mstyle displaystyle="false" scriptlevel="0"> d = 1 </mstyle> </mstyle> <mstyle displaystyle="false" scriptlevel="0"> ( 1 ) k , </mstyle> <mstyle displaystyle="false" scriptlevel="0"> <mstyle displaystyle="false" scriptlevel="0"> d = p 1 p 2 . . . p k    ,    p 1 , p 2 , . . . </mstyle> <mtext> 均为互异质数 </mtext> </mstyle> <mstyle displaystyle="false" scriptlevel="0"> 0 , </mstyle> <mstyle displaystyle="false" scriptlevel="0"> <mtext> 其他情况 </mtext> </mstyle> \mu(d)= \begin{cases} 1, & \text {$d=1$} \\ (-1)^k, & \text{$d=p_1*p_2*...*p_k\;,\;p_1,p_2,...$均为互异质数} \\ 0,& \text{其他情况} \end{cases} μ(d)=1,(1)k,0,d=1d=p1p2...pk,p1,p2,...均为互异质数其他情况

2.性质:

(1) 积性函数,即如果满足 a a a b b b 互质,那么就会满足 f ( a b ) = f ( a ) f ( b ) f(a*b)=f(a)*f(b) f(ab)=f(a)f(b)

(2) 对任意的正整数 n n n ,当 n > 1 n>1 n>1时,其所有因子的莫比乌斯函数值相加为0,
即:
<munder> d n </munder> μ ( d ) = { <mstyle displaystyle="false" scriptlevel="0"> 1 , </mstyle> <mstyle displaystyle="false" scriptlevel="0"> <mtext>   </mtext> n = 1 </mstyle> <mstyle displaystyle="false" scriptlevel="0"> 0 , </mstyle> <mstyle displaystyle="false" scriptlevel="0"> <mtext>   </mtext> n > 1 </mstyle> \sum_{d|n}{\mu(d)}=\begin{cases} 1,&\ n=1 \\ 0,& \ n>1 \end{cases} dnμ(d)={1,0, n=1 n>1
证明
n = 1 n=1 n=1 时,显然成立;
n > 1 n>1 n>1 时,
首先,有:
μ ( d ) 0 d = p 1 p 2 . . . p k \mu(d) \neq 0\Longleftrightarrow d=p_1*p_2* ... *p_k μ(d)=0d=p1p2...pk
对于 μ ( d ) = 0 \mu(d)=0 μ(d)=0 的因子,我们可以不用考虑,下面仅对 μ ( d ) 0 \mu(d)\neq 0 μ(d)=0 的因子讨论。
那么对于一个含有 r r r 的质因子的因子 d d d μ ( d ) = C k r ( 1 ) r \mu(d)=C_k^r*(-1)^r μ(d)=Ckr(1)r
所以
<munder> d n </munder> μ ( d ) = <munderover> i = 0 k </munderover> C k i ( 1 ) i \sum_{d|n}{\mu(d)}=\sum_{i=0}^{k}{C_k^i*(-1)^i} dnμ(d)=i=0kCki(1)i
又根据二项式定理:
( x + y ) n = <munderover> i = 0 n </munderover> C n i x i y n i (x+y)^n=\sum_{i=0}^n{C_n^i*x^i*y^{n-i}} (x+y)n=i=0nCnixiyni
x = 1 , y = 1 x=-1,y=1 x=1,y=1,有
<munderover> i = 0 k </munderover> C k i ( 1 ) i = <munderover> i = 0 k </munderover> C k i x i y k i = 0 \sum_{i=0}^{k}{C_k^i*(-1)^i}=\sum_{i=0}^k{C_k^i*x^i*y^{k-i}}=0 i=0kCki(1)i=i=0kCkixiyki=0
所以,
<munder> d n </munder> μ ( d ) = 0 \sum_{d|n}{\mu(d)}=0 dnμ(d)=0
即证。

(3) 对任意正整数 n n n ,有:
<munder> d n </munder> μ ( d ) d = φ ( n ) n \sum_{d|n}{\frac{\mu(d)}{d}}=\frac{\varphi(n)}{n} dndμ(d)=nφ(n)

证明
先证:
n = <munder> d n </munder> φ ( d ) n=\sum_{d|n}{\varphi(d)} n=dnφ(d)

令:
f ( n ) = <munder> d n </munder> φ ( d ) f(n)=\sum_{d|n}{\varphi(d)} f(n)=dnφ(d)
有:
f ( n ) f ( m ) = <munder> i n </munder> φ ( i ) <munder> j m </munder> φ ( j ) f(n)*f(m)=\sum_{i|n}{\varphi(i)}*\sum_{j|m}{\varphi(j)} f(n)f(m)=inφ(i)jmφ(j)
= <munder> i n </munder> <munder> j m </munder> φ ( i ) φ ( j ) =\sum_{i|n}{\sum_{j|m}\varphi(i)*\varphi(j)} =injmφ(i)φ(j)
因为欧拉函数为积性函数,所以:
= <munder> i n </munder> <munder> j m </munder> φ ( i j ) =\sum_{i|n}{\sum_{j|m}{\varphi(i*j)}} =injmφ(ij)
= <munder> d n m </munder> φ ( d ) =\sum_{d|nm}{\varphi(d)} =dnmφ(d)
= f ( n m ) =f(n*m) =f(nm)
所以 f ( n ) f(n) f(n) 是积性函数。
根据唯一分解定理:
n = p 1 a 1 p 2 a 2 . . . p k a k n=p_1^{a_1}*p_2^{a_2}*...*p_k^{a_k} n=p1a1p2a2...pkak
所以:
f ( n ) = f ( p 1 a 1 p 2 a 2 . . . p k a k ) = f ( p 1 a 1 ) f ( p 2 a 2 ) . . . f ( p k a k ) f(n)=f(p_1^{a_1}*p_2^{a_2}*...*p_k^{a_k})=f(p_1^{a_1})*f(p_2^{a_2})*...*f(p_k^{a_k}) f(n)=f(p1a1p2a2...pkak)=f(p1a1)f(p2a2)...f(pkak)
根据定义,有: f ( p a ) = φ ( 1 ) + φ ( p ) + φ ( p 2 ) + . . + φ ( p a ) f(p^{a})=\varphi(1)+\varphi(p)+\varphi(p^2)+..+\varphi(p^{a}) f(pa)=φ(1)+φ(p)+φ(p2)+..+φ(pa)
由欧拉函数性质,当 n = p k n=p^k n=pk p p p 为素数), φ ( n ) = p k p k 1 \varphi(n)=p^k-p^{k-1} φ(n)=pkpk1,有:
f ( p a ) = 1 + ( p 1 ) + ( p 2 p ) + . . . + ( p a p a 1 ) = p a f(p^a)=1+(p-1)+(p^2-p)+...+(p^a-p^{a-1})=p^a f(pa)=1+(p1)+(p2p)+...+(papa1)=pa
所以:
f ( n ) = p 1 a 1 p 2 a 2 . . . p k a k = n f(n)=p_1^{a_1}*p_2^{a_2}*...*p_k^{a_k}=n f(n)=p1a1p2a2...pkak=n
所以 n = <munder> d n </munder> φ ( d ) n=\sum_{d|n}{\varphi(d)} n=dnφ(d)
知道这个后,就可以证明性质 ( 3 ) (3) (3) 了。
F ( n ) = n , f ( n ) = φ ( n ) F(n)=n,f(n)=\varphi(n) F(n)=n,f(n)=φ(n)
所以, F ( n ) = <munder> d n </munder> f ( d ) F(n)=\sum_{d|n}{f(d)} F(n)=dnf(d)
很明显符合莫比乌斯反演的约数形式,
反演得: f ( n ) = <munder> d n </munder> μ ( d ) F ( n d ) = <munder> d n </munder> μ ( d ) n d f(n)=\sum_{d|n}{\mu(d)F(\frac{n}{d})}=\sum_{d|n}{\mu(d)*\frac{n}{d}} f(n)=dnμ(d)F(dn)=dnμ(d)dn
所以: f ( n ) = n <munder> d n </munder> μ ( d ) d f(n)=n*\sum_{d|n}{\frac{\mu(d)}{d}} f(n)=ndndμ(d)
即: <munder> d n </munder> μ ( d ) d = φ ( n ) n \sum_{d|n}{\frac{\mu(d)}{d}}=\frac{\varphi(n)}{n} dndμ(d)=nφ(n)
证毕。

参考博客1
参考博客2

3.线性筛法(基于欧拉筛)
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
vector<int>prime;
int mob[N];
bool vis[N];
void mobius()
{
    prime.clear();
    memset(vis,0,sizeof(vis));
    mob[1]=1;//莫比乌斯函数第一类情况
    for(int i=2;i<N;i++)
    {
        if(!vis[i])
        {
            prime.push_back(i);
            mob[i]=-1;//素数
        }
        for(int j=0;j<prime.size()&&prime[j]*i<N;j++)
        {
            int tmp=i*prime[j];
            vis[tmp]=1;
            if(i%prime[j]==0)
            {
                mob[tmp]=0;//其他情况,因为prime[j]是i的因子,所以k的因子中含有的prime[j]的个数不是1
                break;
            }
            else
               mob[tmp]=-mob[i];//积性函数的性质
        }
    }
}
int main()
{
    mobius();
    for(int i=1;i<=10;i++)
        cout<<mob[i]<<endl;
    return 0;
}
二.莫比乌斯反演:

  当一个函数 F ( n ) F(n) F(n) 很好求时,而其可以写成其 约数 或 倍数 d d d 的函数 f ( d ) f(d) f(d) f ( d ) f(d) f(d) 很不好求时,我们可以通过莫比乌斯反演利用 F ( n ) F(n) F(n) 反推 f ( d ) f(d) f(d),从而快速求解 f ( d ) f(d) f(d)

F ( n ) F(n) F(n) f ( n ) f(n) f(n) 是定义在非负整数集合上的两个函数。注意 n n n d d d 不要弄混

1.约数形式:

F ( n ) = <munder> d n </munder> f ( d ) f ( n ) = <munder> d n </munder> μ ( d ) F ( n d ) F(n)=\sum_{d|n}{f(d)} \Longrightarrow f(n)=\sum_{d|n}{\mu(d)*F(\frac{n}{d})} F(n)=dnf(d)f(n)=dnμ(d)F(dn)

证明

d n μ ( d ) F ( n d ) = d n μ ( d ) k n d f ( k ) \sum_{d|n}{\mu(d)*F(\frac{n}{d})}= \sum_{d|n}{\mu(d)*\sum_{k|\frac{n}{d}}{f(k)}} dnμ(d)F(dn)=dnμ(d)kdnf(k)

= k n f ( k ) d n k μ ( d ) =\sum_{k|n}{f(k) \sum_{d|\frac{n}{k}}{\mu(d)}} =knf(k)dknμ(d) = f ( n ) =f(n) =f(n)

( k d μ ( d ) f ( k ) , f ( k ) μ ( d ) ) (k和d是等价的,原来是一个\mu(d)对应多个f(k),现在是一个f(k)对应多个\mu(d)) (kdμ(d)f(k),f(k)μ(d))

对于 d n k μ ( d ) \sum_{d|\frac{n}{k}}{\mu(d)} dknμ(d) ,由莫比乌斯函数的性质,当且仅 n k = 1 \frac{n}{k}=1 kn=1 时,其值等于1,否则等于0。

2.倍数形式:

F ( n ) = <munder> n d </munder> f ( d ) f ( n ) = <munder> n d </munder> μ ( d n ) F ( d ) F(n)=\sum_{n|d}{f(d)} \Longrightarrow f(n)=\sum_{n|d}{\mu(\frac{d}{n})F(d)} F(n)=ndf(d)f(n)=ndμ(nd)F(d)

证明(同理):

k = d n k=\frac{d}{n} k=nd,

n d μ ( d n ) F ( d ) \sum_{n|d}{\mu(\frac{d}{n})F(d)} ndμ(nd)F(d)

= k = 1 + μ ( k ) F ( n k ) =\sum_{k=1}^{+\infty}{\mu(k)F(n*k)} =k=1+μ(k)F(nk)

= k = 1 + μ ( k ) n k t f ( t ) =\sum_{k=1}^{+\infty}{\mu(k)\sum_{nk|t}{f(t)}} =k=1+μ(k)nktf(t)

= n t f ( t ) k t n μ ( k ) = f ( n ) = \sum_{n|t}{f(t)}\sum_{k|\frac{t}{n}}{\mu(k)}=f(n) =ntf(t)kntμ(k)=f(n)

三.常见应用:
1. g c d ( i , j ) gcd(i,j) gcd(i,j) 相关问题:

一般先将其转化为求 i = 1 n j = 1 m [ g c d ( i , j ) = = 1 ] \sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==1] i=1nj=1m[gcd(i,j)==1] ,然后利用数论分块解决。

求解 i = 1 n j = 1 m [ g c d ( i , j ) = = 1 ] \sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==1] i=1nj=1m[gcd(i,j)==1] 的过程:

f ( d ) = i = 1 n j = 1 m [ g c d ( i , j ) = = d ] , n u m = m i n ( n , m ) f(d)=\sum_{i=1}^{n}{\sum_{j=1}^{m}{[gcd(i,j)==d]}}, num=min(n,m) f(d)=i=1nj=1m[gcd(i,j)==d],num=min(n,m)

F ( d ) = f ( d ) + f ( 2 d ) + f ( 3 d ) + . . . + f ( k d ) = d n n u m f ( n ) F(d)=f(d)+f(2d)+f(3d)+...+f(kd)=\sum_{d|n}^{num}{f(n)} F(d)=f(d)+f(2d)+f(3d)+...+f(kd)=dnnumf(n)

F ( d ) F(d) F(d) 表示 g c d ( i , j ) gcd(i,j) gcd(i,j) d d d 的倍数的二元组的个数,显然 F ( d ) = n d m d F(d)=\lfloor\frac{n}{d}\rfloor* \lfloor\frac{m}{d}\rfloor F(d)=dndm,容易求得。这样就可以通过 F ( d ) F(d) F(d) 来求 f ( d ) f(d) f(d)了。

由反演公式,得:

f ( d ) = d n n u m μ ( n d ) F ( n ) = d n n u m μ ( n d ) n n m n f(d)=\sum_{d|n}^{num}{\mu(\frac{n}{d})F(n)}=\sum_{d|n}^{num}{\mu(\frac{n}{d})*\lfloor \frac{n}{n}\rfloor *\lfloor \frac{m}{n}\rfloor} f(d)=dnnumμ(dn)F(n)=dnnumμ(dn)nnnm

(向下取整括号中,上面的 n , m n,m n,m 是范围,下面的 n n n 是变量,注意区分)

d = 1 d=1 d=1时,有:(记住)

f ( 1 ) = i = 1 n j = 1 m [ g c d ( i , j ) = = 1 ] = i = 1 m i n ( n , m ) μ ( i ) n i m i f(1)=\sum_{i=1}^{n}{\sum_{j=1}^{m}{[gcd(i,j)==1]}}=\sum_{i=1}^{min(n,m)}{\mu(i)*\lfloor \frac{n}{i} \rfloor *\lfloor \frac{m}{i} \rfloor} f(1)=i=1nj=1m[gcd(i,j)==1]=i=1min(n,m)μ(i)inim

先预处理出莫比乌斯函数的前缀和,然后用数论分块处理。

各种类型分析及常用方法

<mark>重点【反演解题套路】</mark>:

[ g c d ( i , j ) = 1 ] = <munder> d g c d ( i , j ) </munder> μ ( d ) = <munder> d i , d j </munder> μ ( d ) [gcd(i,j)=1]=\sum_{d|gcd(i,j)}{\mu(d)}=\sum_{d|i,d|j}{\mu(d)} [gcd(i,j)=1]=dgcd(i,j)μ(d)=di,djμ(d)
常见应用过程:

i = 1 n j = 1 m [ g c d ( i , j ) = 1 ] \sum_{i=1}^{n}{\sum_{j=1}^{m}{[gcd(i,j)=1]}} i=1nj=1m[gcd(i,j)=1]

= i = 1 n j = 1 m d i , d j μ ( d ) =\sum_{i=1}^{n}{\sum_{j=1}^{m}{\sum_{d|i,d|j}{\mu(d)}}} =i=1nj=1mdi,djμ(d)

= d = 1 m i n ( n , m ) μ ( d ) n d m d =\sum_{d=1}^{min(n,m)}{\mu(d)*\lfloor \frac{n}{d} \rfloor *\lfloor\frac{m}{d}}\rfloor =d=1min(n,m)μ(d)dndm(改变枚举顺序)

证明
因为莫比乌斯函数性质 ( 2 ) (2) (2): [ n = 1 ] = <munder> d n </munder> μ ( d ) [n=1]=\sum_{d|n}{\mu(d)} [n=1]=dnμ(d)
问题

1.求 i = 1 n j = 1 m [ g c d ( i , j ) = d ] ( n m ) \sum_{i=1}^{n}{\sum_{j=1}^{m}{[gcd(i,j)=d]}}(n\leq m) i=1nj=1m[gcd(i,j)=d](nm)

A N S = i = 1 n j = 1 m d g c d ( i , j ) μ ( d ) = i = 1 n j = 1 m d i , d j μ ( d ) ANS=\sum_{i=1}^{n}{\sum_{j=1}^{m}{\sum_{d|gcd(i,j)}{\mu(d)}}}=\sum_{i=1}^{n}{\sum_{j=1}^{m}{\sum_{d|i,d|j}{\mu(d)}}} ANS=i=1nj=1mdgcd(i,j)μ(d)=i=1nj=1mdi,djμ(d)

= d = 1 n ( μ ( d ) n d m d ) =\sum_{d=1}^{n}{(\mu(d)*\lfloor \frac{n}{d}\rfloor*\lfloor \frac{m}{d}\rfloor)} =d=1n(μ(d)dndm)(改变枚举顺序,常用的技巧)

四.例题:

1.hdu1695:

先附上一篇详解和思路
主要是利用莫比乌斯反演的性质来构造函数,同时利用了莫比乌斯反演的第二个函数关系。还有思维的转化。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int mu[N];
bool vis[N];
vector<int>prime;
void mobius()
{
    memset(mu,0,sizeof(mu));
    memset(vis,0,sizeof(vis));
    prime.clear();
    mu[1]=1;
    for(int i=2;i<N;i++)
    {
        if(!vis[i])
        {
            prime.push_back(i);
            mu[i]=-1;
        }
        for(int j=0;j<prime.size()&&i*prime[j]<N;j++)
        {
            int tmp=i*prime[j];
            vis[tmp]=1;
            if(i%prime[j]==0)
            {
                mu[tmp]=0;
                break;
            }
            else
                mu[tmp]=-mu[i];
        }
    }
}
int main()
{
    int T,cas=0;
    mobius();
    scanf("%d",&T);
    while(T--)
    {
        int a,b,c,d,k;
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
        printf("Case %d: ",++cas);
        if(k==0)
        {
            puts("0");
            continue;
        }
        b/=k;
        d/=k;
        long long ans1=0,ans2=0;
        for(int i=1;i<=min(b,d);i++)
            ans1+=(long long)mu[i]*(b/i)*(d/i);
        for(int i=1;i<=min(b,d);i++)
            ans2+=(long long)mu[i]*(min(b,d)/i)*(min(b,d)/i);
        printf("%lld\n",ans1-ans2/2);
    }
    return 0;
}

2.hdu6390:

欧拉函数的性质+莫比乌斯函数性质的运用
已知:

求:

推导:

一直tle,把数据类型改了一下,竟然就过了,玄学。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
int n,m;
ll p,ans;
ll c[N],inv[N];
int prime[N];
bool vis[N];
int mu[N],phi[N];
void mobius_euler()
{
    memset(vis,0,sizeof(vis));
    mu[1]=1;
    phi[1]=1;
    int cnt=0;
    for(int i=2;i<N;i++)
    {
        if(!vis[i])
        {
            prime[++cnt]=i;
            mu[i]=-1;
            phi[i]=i-1;
        }
        for(int j=1;j<=cnt&&i*prime[j]<N;j++)
        {
            int tmp=i*prime[j];
            vis[tmp]=1;
            if(i%prime[j]==0)
            {
                mu[tmp]=0;
                phi[tmp]=phi[i]*prime[j];
                break;
            }
            else
            {
                mu[tmp]=-mu[i];
                phi[tmp]=phi[i]*phi[prime[j]];
            }
        }
    }
}
void init()
{
    inv[1]=1;
    for(int i=2;i<=min(n,m);i++)//递推求逆元
        inv[i]=inv[p%i]*(ll)(p-p/i)%p;
    for(int i=1;i<=min(n,m);i++)
        c[i]=(ll)i*inv[phi[i]]%p;
}
ll g(int x,int y)
{
    ll res=0;
    for(int i=1;i<=min(x,y);i++)
        res=(res+(ll)mu[i]*(x/i)*(y/i))%p;
    return res;
}
int main()
{
    int t;
    scanf("%d",&t);
    mobius_euler();
    while(t--)
    {
        scanf("%d%d%lld",&m,&n,&p);
        ans=0;
        init();
        for(int i=1;i<=min(n,m);i++)
            ans=(ans+c[i]*g(m/i,n/i))%p;
        printf("%lld\n",ans);
    }
    return 0;
}

3.bzoj 2301:【莫比乌斯反演+容斥】

#include <bits/stdc++.h>
using namespace std;
const int N=5e4+5;
vector<int>prime;
bool vis[N];
int mu[N],sum[N];
void mobius()
{
    memset(vis,0,sizeof(vis));
    memset(mu,0,sizeof(mu));
    memset(sum,0,sizeof(sum));
    prime.clear();
    mu[1]=1;
    for(int i=2;i<N;i++)
    {
        if(!vis[i])
        {
            prime.push_back(i);
            mu[i]=-1;
        }
        for(int j=0;j<prime.size()&&i*prime[j]<N;j++)
        {
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                mu[i*prime[j]]=0;
                break;
            }
            else
                mu[i*prime[j]]=-mu[i];
        }
    }
    for(int i=1;i<N;i++)//莫比乌斯函数前缀和
        sum[i]=sum[i-1]+mu[i];
}
int solve(int n,int m)
{
    int k=min(n,m),res=0;
    for(int l=1,r=1;l<=k;l=r+1)
    {
        r=min(k,min(n/(n/l),m/(m/l)));
        res+=(sum[r]-sum[l-1])*(n/l)*(m/l);
    }
    return res;
}
int main()
{
    int a,b,c,d,k,n;
    mobius();
    scanf("%d",&n);
    while(n--)
    {
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
        int ans=solve(b/k,d/k)+solve((a-1)/k,(c-1)/k)-solve(b/k,(c-1)/k)-solve((a-1)/k,d/k);//容斥
        printf("%d\n",ans);
    }
    return 0;
}
/* 2 2 5 1 5 1 1 5 1 5 2 */

4.bzoj2005-能量采集:

枚举d.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
bool vis[N];
int mu[N],sum[N];
vector<int>prime;
void mobius()
{
    memset(vis,0,sizeof(vis));
    memset(mu,0,sizeof(mu));
    memset(sum,0,sizeof(sum));
    prime.clear();
    mu[1]=1;
    for(int i=2;i<N;i++)
    {
        if(!vis[i])
        {
            prime.push_back(i);
            mu[i]=-1;
        }
        for(int j=0;j<prime.size()&&i*prime[j]<N;j++)
        {
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                mu[i*prime[j]]=0;
                break;
            }
            else
                mu[i*prime[j]]=-mu[i];
        }
    }
    for(int i=1;i<N;i++)
        sum[i]=sum[i-1]+mu[i];
}
ll solve(int n,int m)
{
    int k=min(n,m);
    int tn=n,tm=m,tk=k;
    ll res=0;
    for(int i=1;i<=k;i++)//gcd==i
    {
        tn=n/i;
        tm=m/i;
        tk=min(tn,tm);
        for(int l=1,r=1;l<=tk;l=r+1)
        {
            r=min(min(tn/(tn/l),tm/(tm/l)),tk);
            res+=((1LL)*(sum[r]-sum[l-1])*(tm/l)*(tn/l))*(1LL)*i;//注意*i,否则,只算了个数。
        }
    }
    return res;
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        mobius();
        printf("%lld\n",2*solve(n,m)-(1LL)*n*m);//防爆
    }
    return 0;
}

5.P2257 YY的GCD:

  一开始的做法是直接暴力,先筛出 [ 1 , 1 e 7 ] [1,1e7] [1,1e7] 内的所有素数及莫比乌斯函数函数值,然后暴力枚举 m i n ( n , m ) min(n,m) min(n,m) 内的素数,进行数论分块。只过了一半的测试点就 t t t 了。

看了题解后发现还可以继续化简:

A N S = p = 1 m i n ( n , m ) i s p r i m e ( p ) i = 1 n j = 1 m [ g c d ( i , j ) = = p ] ANS=\sum_{p=1}^{min(n,m)}{isprime(p)}*\sum_{i=1}^{n}{\sum_{j=1}^{m}{[gcd(i,j)==p]}} ANS=p=1min(n,m)isprime(p)i=1nj=1m[gcd(i,j)==p]

= p = 1 m i n ( n , m ) i s p r i m e ( p ) i = 1 n p j = 1 m p [ g c d ( i , j ) = = 1 ] =\sum_{p=1}^{min(n,m)}{isprime(p)*\sum_{i=1}^{\lfloor \frac{n}{p} \rfloor}}{\sum_{j=1}^{\lfloor \frac{m}{p}\rfloor}{[gcd(i,j)==1]}} =p=1min(n,m)isprime(p)i=1pnj=1pm[gcd(i,j)==1](我到这步就直接算了)

= p = 1 m i n ( n , m ) i s p r i m e ( p ) d = 1 m i n ( n p , m p ) ( μ ( d ) n d p m d p ) =\sum_{p=1}^{min(n,m)}{isprime(p)*\sum_{d=1}^{min(\lfloor\frac{n}{p}\rfloor,\lfloor\frac{m}{p}\rfloor)}{(\mu(d)*\lfloor\frac{n}{d*p}\rfloor}*\lfloor\frac{m}{d*p}\rfloor)} =p=1min(n,m)isprime(p)d=1min(pn,pm)(μ(d)dpndpm)

T = d p , t = p T=d*p,t=p T=dp,t=p

= t = 1 m i n ( n , m ) i s p r i m e ( t ) t T m i n ( n , m ) ( μ ( t ) n T m T ) =\sum_{t=1}^{min(n,m)}{isprime(t)*\sum_{t|T}^{min(n,m)}{(\mu(t)*\lfloor\frac{n}{T}\rfloor*\lfloor\frac{m}{T}\rfloor)}} =t=1min(n,m)isprime(t)tTmin(n,m)(μ(t)TnTm)

= T = 1 m i n ( n , m ) n T m T t T , t p r i m e μ ( T t ) =\sum_{T=1}^{min(n,m)}{\lfloor\frac{n}{T}\rfloor*\lfloor\frac{m}{T}\rfloor*\sum_{t|T,t\in prime}{\mu(\frac{T}{t})}} =T=1min(n,m)TnTmtT,tprimeμ(tT)

到此化简结束。
前半部分可以通过数论分块处理,后面可以在求莫比乌斯反演的时候预处理。
AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e7+5;
vector<int> prime;
bool vis[N];
int mu[N];
ll sum[N],T[N];
void euler()
{
    mu[1]=1;
    for(int i=2;i<=N-5;i++)
    {
        if(!vis[i])
        {
            prime.push_back(i);
            mu[i]=-1;
        }
        for(int j=0;j<prime.size()&&i*prime[j]<=N-5;j++)
        {
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                mu[i*prime[j]]=0;
                break;
            }
            else
                mu[i*prime[j]]=-mu[i];
        }
    }
    for(int i=0;i<prime.size();i++)
    {
        for(int j=1;j*prime[i]<=N-5;j++)
            T[j*prime[i]]+=mu[j];
    }
    for(int i=1;i<=N-5;i++)
        sum[i]=sum[i-1]+T[i];
}
ll solve(int n,int m)
{
    ll res=0;
    int minn=min(n,m);
    for(int l=1,r=1;l<=minn;l=r+1)
    {
        r=min(min(m/(m/l),n/(n/l)),minn);//cout<<"r= "<<r<<endl;
        res+=1LL*(sum[r]-sum[l-1])*(n/l)*(m/l);
    }
    return res;
}
int main()
{
    int t,n,m;
    euler();//cout<<prime.size()<<endl;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        ll ans=solve(n,m);
        printf("%lld\n",ans);
    }
    return 0;
}

全部评论

相关推荐

头像
05-09 00:54
已编辑
前端工程师
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务