欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

关于Mobius反演

程序员文章站 2022-10-16 15:44:41
欧拉函数 $\varphi$ $\varphi(n)=$表示不超过 $n$ 且与 $n$ 互质的正整数的个数 $$\varphi(n)=n\cdot \prod_{i=1}^{s}(1 \frac{1}{p_i})$$ 其中 $n = {p_1}^{\alpha1} \cdot {p_2}^{\al ......

欧拉函数 \(\varphi\)

\(\varphi(n)=\)表示不超过 \(n\) 且与 \(n\) 互质的正整数的个数
\[\varphi(n)=n\cdot \prod_{i=1}^{s}(1-\frac{1}{p_i})\]
其中 \(n = {p_1}^{\alpha1} \cdot {p_2}^{\alpha2} \cdots {p_s}^{\alpha s} \cdot\)\(n\) 的标准分解。
由此易见 \(\text{euler}\) 函数是积性函数。

线性求 \(\text{euler}\) 函数:

#define int long long
int phi[3000005];
int n=3000000;
bool mark[3000005];
int prime[1000005];
int tot;
void getphi()
{
    phi[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(mark[i]==false)
        {
            prime[++tot]=i;
            phi[i]=i-1;
        }
        for(int j=1;j<=tot;j++)
        {
            if(i*prime[j]>n)
            {
                break;
            }
            mark[i*prime[j]]=true;
            if(i%prime[j]==0)
            {
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            phi[i*prime[j]]=phi[i]*phi[prime[j]];
        }
    }
    for(int i=1;i<=n;i++)
    {
        phi[i]+=phi[i-1];
    }
}

\(\text{mobius}\)函数 \(\mu(n)\)

\[ \mu(n)= \begin{cases} 1&n=1\\ 0&n\text{ 含有平方因子}\\ (-1)^k&k\text{ 为 }n\text{ 的本质不同质因子个数}\ \end{cases} \]
证明:
\[ \varepsilon(n)= \begin{cases} 1&n=1\\ 0&n\neq 1\ \end{cases} \]

其中 \(\displaystyle\varepsilon(n)=\sum_{d\mid n}\mu(d)\)\(\varepsilon=\mu*1\)

\(\displaystyle n=\prod_{i=1}^k{p_i}^{c_i},n'=\prod_{i=1}^k p_i\)

那么 \(\displaystyle\sum_{d\mid n}\mu(d)=\sum_{d\mid n'}\mu(d)=\sum_{i=0}^k c_k^i\cdot(-1)^k\)

根据二项式定理,易知该式子的值在 \(k=0\)\(n=1\) 时值为 \(1\) 否则为 \(0\) ,这也同时证明了 \(\displaystyle\sum_{d\mid n}\mu(d)=[n=1]\)

#define int long long
int mu[3000005];
int n=3000000;
bool mark[3000005];
int prime[1000005];
int tot;
void getmu()
{
    mu[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(mark[i]==false)
        {
            prime[++tot]=i;
            mu[i]=-1;
        }
        for(int j=1;j<=tot;j++)
        {
            if(i*prime[j]>n)
            {
                break;
            }
            mark[i*prime[j]]=true;
            if(i%prime[j]==0)
            {
                mu[i*prime[j]]=0;
                break;
            }
            mu[i*prime[j]]=-mu[i];
        }
    }
}

\(\text{dirichlet}\)卷积

\(\text{id}:\text{id(i)=i}\)
\(\text{1}:\text{1(i)=1}\)
定义两个数论函数的\(\text{dirichlet}\)卷积为:
\[(f*g)(n)=\sum_{d|n}({f(d)\times g(\frac{n}{d})}) \]
性质:\(\text{dirichlet}\)卷积满足交换律和结合律。
单位元:\(\varepsilon\)\(\varepsilon(n)=[n==1]\),任何函数卷\(\varepsilon\)都为其本身.
\(1*\mu=\varepsilon\)
\(\mu * \text{id} = \varphi\)
\(1*\text{id}=\sigma\)

莫比乌斯反演

公式:设 \(f(n),g(n)\) 为两个数论函数。
如果有
\[ f(n)=\sum_{d\mid n}g(d) \]
那么有
\[ g(n)=\sum_{d\mid n}\mu(\frac{n}{d})f(d) \]
证明:
原命题等价于:已知 \(f=g*1\) ,证明 \(g=f*\mu\)
显然: \(f*\mu=g*1*\mu= g*\varepsilon=g\) (其中 \(1*\mu=\varepsilon\)

同时,还有另一种\(\text{mobius}\)反演:
如果有
\[ f(n)=\sum_{n\mid d}g(d) \]
那么有
\[ g(n)=\sum_{n\mid d}\mu(\frac{d}{n})f(d) \]

整除分块

当遇到形如
\[\sum_{i=1}^{n}\lfloor \frac{n}{i} \rfloor\]
的柿子时。
可以采用\(o(\sqrt {n})\)复杂度的算法:整除分块
易证:对于部分连续的\(i\)\(\frac{n}{i}\)的值是相同的,考虑把它们合并计算,可以发现发现对于每一个值相同的块,它的最后一个数是n/(n/i)
简略证明:\(\frac{n}{i}\)就是所求的值,设为\(x\),那么可证对于值\(x\),它所在的块的最后一个数是\(\frac{n}{x}\)

  • 证明:反证法:对于数\(\frac{n}{x}+1\),它所在的块的值为\(\frac{n}{\frac{n}{x}+1}\),且\(\frac{n}{\frac{n}{x}+1}-x=\frac{x^2}{n+x}>0\)。$\therefore \(数\)\frac{n}{x}+1 \(和数\)\frac{n}{x}$不在同一个块中。
    然后,原命题得证。

所以,易得计算原式方法。

for(int l=1,r;l<=n;l=r+1)
{
    r=n/(n/l);
    ans+=(r-l+1)*(n/l);
}

p2257 yy的gcd

\(f(d)=\sum_{i=1}^{n}\sum_{i=1}^{m}[gcd(i,j)=d]\)
\(f(n)=\sum_{n\mid d}f(d)=\lfloor \frac{n}{n} \rfloor \times \lfloor \frac{m}{n} \rfloor\)
由莫比乌斯反演:\(f(n)=\sum_{n|d}\mu(\frac{d}{n})f(d)\)

\(ans=\sum_{i=1}^{n}\sum_{i=1}^{m}[gcd(i,j)=prim]\)
\(=\sum_{p\in prim}\sum_{i=1}^{n}\sum_{i=1}^{m}[gcd(i,j)=p]\)
\(=\sum_{p\in prim}f(p)\)
\(=\sum_{p\in prim}\sum_{p|d}\mu(\frac{d}{p})f(d)\)
改为枚举\(\frac{d}{p}\)
\(ans=\sum_{p\in prim}\sum_{i}^{min(\lfloor \frac{n}{p} \rfloor,\lfloor \frac{m}{p} \rfloor)}\mu(i)f(dp)\)
\(=\sum_{p\in prim}\sum_{d}^{min(\lfloor \frac{n}{p} \rfloor,\lfloor \frac{m}{p} \rfloor)}\mu(d) \times \lfloor \frac{n}{dp} \rfloor \times \lfloor \frac{m}{dp} \rfloor\)
\(dp=t,t=p\)
\(ans=\sum_{t\in prim}\sum_{d}^{min(\lfloor \frac{n}{t} \rfloor,\lfloor \frac{m}{t} \rfloor)}\mu(\frac{t}{t}) \times \lfloor \frac{n}{t} \rfloor \times \lfloor \frac{m}{t} \rfloor\)
\(=\sum_{t=1}^{min(n,m)}\sum_{t\in prim,t|t}\mu(\frac{t}{t}) \times \lfloor \frac{n}{t} \rfloor \times \lfloor \frac{m}{t} \rfloor\)
\(=\sum_{t=1}^{min(n,m)}(\lfloor \frac{n}{t} \rfloor \times \lfloor \frac{m}{t} \rfloor) \times \sum_{t\in prim,t|t}\mu(\frac{t}{t})\)

代码:
//sum即为\(\sum_{t\in prim,t|t}\mu(\frac{t}{t})\)的前缀和

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int prime[10000005];
int mu[10000005];
ll f[10000005];
ll sum[10000005];
bool vis[10000005];
int cnt;
void init()
{
    mu[1]=1;
    for(int i=2;i<=10000000;i++)
    {
        if(vis[i]==false)
        {
            mu[i]=-1;
            prime[++cnt]=i;
        }
        for(int j=1;j<=cnt&&i*prime[j]<=10000000;j++)
        {
            vis[i*prime[j]]=true;
            if(i%prime[j]==0)
            {
                break;
            }
            mu[i*prime[j]]=-mu[i];
        }
    }
    for(int i=1;i<=cnt;i++)
    {
        for(int j=1;j*prime[i]<=10000000;j++)
        {
            f[j*prime[i]]+=mu[j];
        }
    }
    for(int i=1;i<=10000000;i++)
    {
        sum[i]=sum[i-1]+f[i];
    }
}
ll solve(int a,int b)//运用整除分块
{
    ll ans=0;
    if(a>b)
    {
        swap(a,b);
    }
    for(int l=1,r=0;l<=a;l=r+1)
    {
        r=min(a/(a/l),b/(b/l));
        ans+=(ll)(sum[r]-sum[l-1])*(a/l)*(b/l);
    }
    return ans;
}
signed main()
{
    init();
    int t;
    cin>>t;
    for(int i=1;i<=t;i++)
    {
        int a,b;
        scanf("%d %d",&a,&b);
        printf("%lld\n",solve(a,b));
    }
    return 0;
}