Dirichlet 卷积是两个定义域在正整数上的函数的如下运算,符号为 $*$

$(f * g)(n) = \sum_{d|n}f(d)g(\frac{n}{d})$

如果不强调 $n$ 可简写为 $f * g$

常用:

$\mu * 1 = \epsilon$

$\phi * 1 = id$

$\epsilon(n) = [n=1]$

$id(n)=n$

 

Mobius 反演是基于 Dirichlet 卷积的一种....化简式子的方法?

比较有用的结论就是 $\mu * 1 = [n=1]$

由这个可以引出两个式子

1.如果 $$F(n) = \sum_{n|d}f(d)$$

则 $$f(n) = \sum_{n|d} F(d)\mu(\lfloor \frac{d}{n} \rfloor)$$

 

2.如果 $$F(n) = \sum_{d|n}f(d)$$

则 $$f(n) = \sum_{d|n} \mu(\lfloor \frac{n}{d} \rfloor)F(d)$$

 

还有一个很好用的东西叫做数论分块,即 $\lfloor \frac{n}{i} \rfloor$ 只有 $\sqrt{n}$ 种取值

 

知道这些就可以做题了

bzoj1101 Zap

求$$\sum_{i=1}^n \sum_{j=1}^m[gcd(i,j)==k]$$

sol:先除以 $k$ ,转化为 $$\sum_{i=1}^x \sum_{j=1}^y[gcd(i,j)==1] \space \space (x = \lfloor \frac{n}{k} \rfloor,y=\lfloor \frac{m}{k} \rfloor)$$

然后发现 $[gcd(i,j)==1]$ 是一个 $[n=1]$ 的形式,我们把它转化成 $\mu * 1$

得到

$$\sum_{i=1}^x \sum_{i=1}^y \sum_{d|gcd(i,j)} \mu(d)$$

因为 $d|(gcd(x,y)$等价于 $d|x$ & $d|y$

而且 $1\thicksim n$ 中满足 $d|x$ 的 $x$ 数量为 $\lfloor \frac{n}{x} \rfloor$

所以原式为 $$\sum_{d=1}^x \mu(d) \lfloor \frac{x}{d} \rfloor \lfloor \frac{y}{d} \rfloor$$

预处理 $\mu$ 的前缀和,数论分块即可

#include<bits/stdc++.h>
#define LL long long
using namespace std;
inline int read()
{
    int x = 0,f = 1;char ch = getchar();
    for(;!isdigit(ch);ch = getchar())if(ch == '-')f = -f;
    for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0';
    return x * f;
}
const int maxn = 50010;
int ntp[maxn],pri[maxn],mu[maxn],tot;
int sum[maxn];
void getmu()
{
    mu[1]=1;
    for(int i=2;i<=50000;i++)
    {
        if(!ntp[i])pri[++tot]=i,mu[i]=-1;
        for(int j=1;j<=tot&&pri[j]*i<=50000;j++)
        {
            ntp[i*pri[j]]=1;
            if(i%pri[j]==0){mu[i*pri[j]]=0;break;}
            else mu[i*pri[j]]=-mu[i];
        }
    }
    for(int i=1;i<=50000;i++)sum[i]=sum[i-1]+mu[i];
} 
int cal(int x,int y)
{
    int ret = 0;
    if(x > y)swap(x,y);
    for(int L=1,R=0;L<=x;L=R+1) 
    {
        R = min(x/(x/L),y/(y/L));
        ret += (x/L) * (y/L) * (sum[R] - sum[L - 1]);
    }return ret;
}
int main()
{
    int T = read();
    getmu();
    while(T--)
    {
        int a = read(),b = read(),d = read();
        printf("%d\n",cal(a / d,b / d));
    }
}
View Code

相关文章:

  • 2021-09-01
  • 2021-07-03
  • 2022-02-08
  • 2022-03-09
  • 2022-03-07
  • 2021-07-15
  • 2021-05-26
  • 2021-07-30
猜你喜欢
  • 2021-12-14
  • 2022-12-23
  • 2021-07-23
  • 2021-04-10
  • 2022-03-08
  • 2021-11-09
  • 2021-08-18
相关资源
相似解决方案