容斥原理/莫比乌斯反演破译密码
Posted skywalker767
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了容斥原理/莫比乌斯反演破译密码相关的知识,希望对你有一定的参考价值。
重学了一下莫反,感觉收获了好多。(
原来你还记得自己学过莫反)
原题链接:https://www.acwing.com/problem/content/217/
题目描述:
达达正在破解一段密码,他需要回答很多类似的问题:
对于给定的整数 a,b 和 d,有多少正整数对 x,y,满足 x≤a,y≤b,并且 gcd(x,y)=d。作为达达的同学,达达希望得到你的帮助。
我们分析一下,题目很明了,要求的就是
g
c
d
(
x
,
y
)
=
d
gcd(x , y) = d
gcd(x,y)=d的个数,转化一下:
x
′
=
x
/
d
,
y
′
=
y
/
d
[
g
c
d
(
x
,
y
)
=
d
]
=
[
g
c
d
(
x
′
,
y
′
)
=
1
]
x' = x / d , y' = y / d\\\\ [gcd(x , y) = d] = [gcd(x' , y') = 1]\\\\
x′=x/d,y′=y/d[gcd(x,y)=d]=[gcd(x′,y′)=1]
这两个是等价的,但是看的时候我还是愣了一下(还是比较笨的),但是仔细思考下,感觉还是很容易证明的。
证明:
首先,x , y 的最大公约数是d,那么我们除去最大公约数,两个数就互质了,这个毋庸置疑,对于每个 g c d ( x , y ) = d gcd(x , y) = d gcd(x,y)=d都如此操作,那么可以证明,这两个的数量是一一对应的。
(这么显然,我还要思考一会,真滴笨!OVQ)
那么我们的问题转化为:
x
≤
a
/
d
x \\le a/d
x≤a/d ,
y
≤
b
/
d
y \\le b/d
y≤b/d ,
g
c
d
(
x
,
y
)
=
1
gcd(x , y)= 1
gcd(x,y)=1的个数,我们考虑容斥原理:互质的数 = 总数 - 不是互质的数,
总数很容易,
a
′
=
a
/
d
,
b
′
=
b
/
d
a' = a / d , b' = b / d
a′=a/d,b′=b/d , 那么总数就是
a
′
∗
b
′
a' * b'
a′∗b′,下面分析下我们要减去的不互质的数:
∑
i
=
2
m
i
n
(
a
,
b
)
[
a
′
i
]
∗
[
b
′
i
]
∗
m
o
b
i
u
s
[
i
]
∑^{min(a,b)}_{i=2} [\\frac{a'}{i}]∗[\\frac{b'}{i}]∗mobius[i]
i=2∑min(a,b)[ia′]∗[ib′]∗mobius[i]
式子上午看的,人是上午没的,我直接喵喵喵?? 愣了一会,发现显然(我是笨比).
证明:
我们要减去的是什么呢?是不互质的数,不互质数是什么呢?是最大公因数不为1的数,不为1,那可以为几呢?不是1就行(废话),我们枚举最大公因数不为1的个数即可。枚举每一个可能的最大公因数,并且计算个数。
当最大公因数是只有一个质因子的时候,我们可以列出:
[
a
′
2
]
∗
[
b
′
2
]
+
[
a
′
3
]
∗
[
b
′
3
]
+
.
.
.
.
.
[\\frac{a'}{2}] * [\\frac{b'}{2}] + [\\frac{a'}{3}] * [\\frac{b'}{3}] + .....
[2a′]∗[2b′]+[3a′]∗[3b′]+.....
最大公因数是2的两对数,实际上就等2的倍数个数相乘, 这两个个数是等同的,同理3也是,但是我们要考虑重复的情况,如6,我们2,3,都枚举了一次,那么会重复,根据容斥原理,我们要减去,最后我们发现,其实符号就是
M
o
b
i
u
s
Mobius
Mobius函数(这个证明是显然的)。以此类推,枚举到
a
′
a'
a′和
b
′
b'
b′中较小的就可以了,因为大于较小的,则式子为0,我们就能推出上面的式子了。(被自己蠢哭了)
那么答案呼之欲出:
a
′
b
′
+
∑
i
=
2
m
i
n
(
a
,
b
)
[
a
′
i
]
∗
[
b
′
i
]
∗
m
o
b
i
u
s
[
i
]
a'b' + ∑^{min(a,b)}_{i=2} [\\frac{a'}{i}]∗[\\frac{b'}{i}]∗mobius[i]\\\\
a′b′+i=2∑min(a,b)[ia′]∗[ib′]∗mobius[i]
我们把这玩意合体一下
∑
i
=
1
m
i
n
(
a
,
b
)
[
a
′
i
]
∗
[
b
′
i
]
∗
m
o
b
i
u
s
[
i
]
∑^{min(a,b)}_{i=1} [\\frac{a'}{i}]∗[\\frac{b'}{i}]∗mobius[i]
i=1∑min(a,b)[ia′]∗[ib′]∗mobius[i]
然后我们发现,高兴的还是有点早,每次都是 O ( n ) O(n) O(n),总体是 O ( n 2 ) O(n^2) O(n2),时间复杂度很大,我们忍受不了。
然后神奇的东西就出现了,我们称之为 “优雅的暴力——分块”。
下面来分析下分块,这个还好!没怎么卡。
首先,我们发现式子里面有很多取整,那么实际上数据应该是一段一段的,我们就可以考虑通过这点来加速,既然这一段都是一样的,我们直接一段一段的算,发现效率可观,可以达到 O ( n n ) ) O(n\\sqrt{n}) ) O(nn)),下面写下分块的原理,我们定义一个 get(x) 函数,这个函数和lowbit函数一样,虽然短小,但是精悍,他主要做的事是:传回当前一样的一段中,下标最大的那个,也就是 a g e t ( x ) + 1 \\frac{a}{get(x) + 1} get(x)+1a就会变小。
int get(int n , int x) {
return n / (n / x);
}
我们说这玩意想着就是一段一段的,那么到底多少呢?答案是: 2 a 2\\sqrt{a} 2a
证明: 我们把1到n分成:1到 a \\sqrt{a} a和 a + 1 \\sqrt{a} + 1 a+1到 n n n,我们发现 a 1 ∼ a \\frac{a}{1 \\sim \\sqrt{a}} 1∼aa,只有 a \\sqrt{a} a