卷积与莫比乌斯反演

卷积与莫比乌斯反演

目录

卷积与莫比乌斯反演

0前言

        0.1前置技能

        0.2问题的引入

1.简单定义

        1.1数论函数的定义

        1.2卷积的定义

        1.3反演的基本形式

2.1莫比乌斯反演

3.1例题:【luogu-P2257 YY的GCD】

题目大意:

solution1

solution2


0.前言

莫比乌斯反演是数论数学中很重要的内容,可以用于解决很多组合数学的问题。

                                                                                                                                                                来源——百度百科

0.1前置技能

 

  • 初一数学水平。
  • 卷积、莫比乌斯函数有简单了解。

0.2问题的引入

OI竞赛中,经常遇到这样一类数学问题:

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

显然,暴力的时间复杂度是O(n)的,显然这个复杂度是我们无法接受的。

然而,倘若我们使用莫比乌斯反演,就能够大大优化其时间复杂度。

 

1.简单定义

 

1.1数论函数的定义

若函数f是正整数域内的函数,则称f数论函数

对于一个数论函数,对于任意互质的正整数a,b,满足f(a)f(b)=f(ab),则称 f积性函数

对于一个数论函数,对于任意的正整数a,b,满足f(a)f(b)=f(ab),则称 f完全积性函数

1.2卷积的定义

有两个数论函数f(x),g(x),则他们的卷积:(f*g)(x)=\sum_{i|x}f(i)g(\frac{x}{i})

易得:若两个数论函数f,g是积性的,那么卷积f*g 也是积性的。

设     n=\sum_{i}p_i^{k_i}     

有以下一些常用的函数:

 

 

  • 元函数:\epsilon (n)=[n==1]
  • 恒等函数:I(n)=1
  • 单位函数:id(n)=n
  • 欧拉函数:\varphi (n)=\prod (p_{i}-1)p_i^{k_i-1}    表示  [1,n]  中与n互质的数的个数。
  • 莫比乌斯函数:\mu (n)=\begin{Bmatrix} 0 & (\exists k_i\geqslant 2)\\ (-1)^k & (\forall k_i<2) \end{Bmatrix}
  • 约数和函数:\sigma (n)=\prod (k_i+1)    表示n的正约数和。 
  • 约数个数函数:  d(n)=\sum_{d|n}1   表示n的正约数个数。 ‘

容易发现如下性质:

 

  • \mu *I=\epsilon
  • \varphi *I=id
  • id*\mu =\varphi
  • I*I=\sigma
  • \sigma *\mu =I
  • 对于任意数论函数f,g   f*I=g\Leftrightarrow g*\mu=f    这是莫比乌斯反演的核心公式。
  • 对于任意数论函数f,f*\epsilon =f

1.3容斥

我们定义一个函数f,再通过f定义函数g,使得:

g_i=\sum_{j\subseteq i}f_{j}

我们可以从 g函数的值 反推出f函数的值。

f_i=\sum_{j\subseteq i}g_{j}(-1)^{|j|-|i|}

倘若我们能快速计算个g函数的值,那么就可以求得f 。

事实上,这与反演的思想有异曲同工之妙。

 

 2.1莫比乌斯反演

在莫比乌斯反演中,我们需要快速求出:

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

\RightarrowF=f*I

\RightarrowF*\mu=f*I*\mu

\RightarrowF*\mu=f*\epsilon

\RightarrowF*\mu =f

因此  f(n)=\sum_{d|n}\mu(d)F(\frac{n}{d})

除此之外,还有    \sum_{d|n}\mu(d)F(\frac{n}{d})\Leftrightarrow \sum_{n|d}\mu(\frac{d}{n})F(d)  

在能够快速求得F函数的情况下,我们就可以很容易地得出f函数的值。

这就是莫比乌斯反演了。

 

3.1例题:【luogu-P2257 YY的GCD】

 

题目大意:

给定N,M

1\leqslant x\leqslant n,1\leqslant y\leqslant m且 gcd(x,y) 为质数的 (x,y) 有多少对。

T=10000    N,M\leqslant 10^7

 

solution1

这一个简单的不使用反演的解法。(事实上就是写出了反演省略的步骤)

显然:

ANS=\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{k\in prime}[gcd(i,j)=k]

把K提出来:

ANS=\sum_{k\in prime} \sum_{i=1}^{n} \sum_{j=1}^{m}[gcd(i,j)=k]

ANS=\sum_{k\in prime} \sum_{i=1}^{\left \lfloor n/k \right \rfloor} \sum_{j=1}^{\left \lfloor m/k \right \rfloor }[gcd(i,j)=1]

ANS=\sum_{k\in prime} \sum_{i=1}^{\left \lfloor n/k \right \rfloor} \sum_{j=1}^{\left \lfloor m/k \right \rfloor }\epsilon (gcd(i,j))

ANS=\sum_{k\in prime} \sum_{i=1}^{\left \lfloor n/k \right \rfloor} \sum_{j=1}^{\left \lfloor m/k \right \rfloor } \(\mu *I)(gcd(i,j))

ANS=\sum_{k\in prime} \sum_{i=1}^{\left \lfloor n/k \right \rfloor} \sum_{j=1}^{\left \lfloor m/k \right \rfloor } \sum_{d|gcd(i,j)}\mu(d)

ANS=\sum_{k\in prime} \sum_{d=1}^{min(\left \lfloor n/k \right \rfloor,\left \lfloor m/k \right \rfloor)}\mu(d)*\left \lfloor n/kd \right \rfloor*\left \lfloor m/kd \right \rfloor

设   T=kd

ANS=\sum_{T=1}^{min(n,m)}\sum_{i|T}\mu(T/i)*\left \lfloor n/T \right \rfloor*\left \lfloor m/T \right \rfloor

ANS=\sum_{T=1}^{min(n,m)}(\sum_{i|T}\mu(T/i))*\left \lfloor n/T \right \rfloor*\left \lfloor m/T \right \rfloor

直接数论分块即可。

 

solution2

这是一个运用反演知识的解法。

设 f(d) 表示满足  gcd(x,y)=d 且 1\leqslant x\leqslant n,1\leqslant y\leqslant m  的 (x,y) 的对数。

设 F(d) 表示满足 d|gcd(x,y) 且 1\leqslant x\leqslant n,1\leqslant y\leqslant m 的 (x,y) 的对数。

那么:

g(x)=\left \lfloor n/x \right \rfloor\left \lfloor m/x \right \rfloor  且  F(x)=\sum_{d|x}^{min(n,m)}f(d)

使用莫比乌斯反演,即得:

f(x)=\sum_{x|d}^{min(n,m)}g(\frac{x}{d})\mu(d)

ANS=\sum_{x} f(x)

便可以得到solution1中的式子,直接数论分块做。

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=1e7+50;
int pnum=0;
bool vis[MAXN];
ll mu[MAXN],Prime[MAXN],sum[MAXN],g[MAXN];
inline int read()
{
	int f=1,x=0; char c=getchar();
	while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }
	while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+c-'0'; c=getchar(); }
	return x*f;
}
void init(int n)
{
	vis[1]=mu[1]=1;
	for (int i=2;i<=n;i++)
	{
		if (!vis[i]) { mu[i]=-1; Prime[++pnum]=i; }
		for (int j=1;j<=pnum&&Prime[j]*i<=n;j++)
		{
			vis[Prime[j]*i]=1;
			if (!(i%Prime[j])) break;
			mu[Prime[j]*i]=-mu[i];
		}
	}
	for (int i=1;i<=n;i++)
	    for (int j=1;j<=pnum&&Prime[j]*i<=n;j++) g[Prime[j]*i]+=mu[i]; 
	for (int i=1;i<=n;i++) sum[i]=sum[i-1]+g[i];
}
int main()
{
	init(1e7);
	int Case=read();
	while (Case--)
	{
		ll n=read(),m=read(),ans=0;
		if (n>m) swap(n,m);
		for (ll l=1,r;l<=n;l=r+1)
		{
			r=min(n/(n/l),m/(m/l));
			ans+=1ll*(n/l)*(m/l)*(sum[r]-sum[l-1]);
		} 
		printf("%lld\n",ans);
	}
	return 0;
}

时间复杂度大概是  O(n lg n+t\sqrt{n}) 。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值