UyHiP 往期趣题整理(6)2017 / 05~07

因为往后只剩 6 个月的题,有些题有好几小问,所以分两篇。

2017-05

这题是 2007-122010-06 题目的延伸,这两道题就等我哪年整理到那儿再说……

(1)设 n>1 是整数,请问对怎样的 n,存在 n 元交换群 (S, +) 以及 S→S 的一一映射 A, B, C,使得 A(x)+B(x)=C(x) 恒成立?

(2)设 n>1 是整数,请问对怎样的 n,存在 n 元群 (S, *) 以及 S→S 的一一映射 A, B, C,使得 A(x)+B(x)=C(x) 恒成立?

2017-06

一个点在数轴上运动,初始时位于 x_0=0 处,第 i 步(i≥1)向右移动距离 Δ_i,到达位置 x_i(即 x_i=x_(i-1)+Δ_i )。已知 Δ_i 服从 [-1, 1] 上的均匀分布且相互独立,问 n 步后该点从未移动到负半轴(即 x_0, ... , x_n 均非负)的概率是多少?

2017-07

(1)设计一个可以在常数时间内完成分配数组空间、取值、修改、初始化为给定值的数组。(时间复杂度的假设参见这里,特别注意的是原生的数组可以在常数时间内分配空间,但是初始值是随机的,如果遍历一遍设置所有元素,显然不是常数时间。)

(2)请在 O(n) 的时间内求出一个长度为 n 的实数数组的中位数。(时间复杂度的假设参见这里,特别注意的是机器可以存储理想实数,并且一些基本操作只需耗费常数时间。)

这里特地再次声明一下,链接中关于时间复杂度的一些假设是理想假设,实际不可能做到;反之利用理想假设,可以做一些实际的算法做不到的事情。例如两个整数数组可以在常数时间内将各分量分别相加,只要将数组中的 n 个整数压到一个超长整数中!虽然实际上没什么用,但很适合作为谜题,这也是 UyHiP 算法谜题系列的目的,而不仅仅是为了简化时间复杂度计算。

不过这两道题都是可用实际可行的算法解决的经典题目。




答案

2017-05

两道题答案相同:当 n 是 4k+2 形整数时不可以,反之可以。(k 是整数的条件就不特别说明了,都懂的)

因为第一小问比第二小问要求严格,所以只要验证 n=4k+2 时无法满足第二小问的条件,其他情况下可以满足第一小问的条件就行。对于 n 为奇数的情况,只需取 S={0, 1, ... , n-1},S 上的加法为模 n 的普通加法(或者换句话说,取 S=Z/nZ),然后令 A(x)=B(x)=x, C(x)=x+x=2x 就行了。

对 n 被 4 整除的情况,令 n=2^k*m(k≥2,m 为奇数),取 S={0, 1}^k×{0, 1, ... , m-1}(即 S 由 k+1 元有序对组成,前 k 个分量为 0 或 1,第 k+1 个分量为 [0, m) 内的整数),S 上的加法为各个分量各自相加对 2 或 m 取模(或者换句话说,取 S=(Z/2Z)*...(Z/2Z)*(Z/mZ)),然后令

A(x)=x,

B((x_1, x_2, ... , x_k, x_(k+1)))=(x_2, x_3, ... , x_k, x_1+x_k, x_(k+1)),

显然它们都是一一映射(函数值唯一决定自变量),它们之和等于

C((x_1, x_2, ... , x_k, x_(k+1)))=(x_1+x_2, x_2+x_3, ... , x_(k-1)+x_k, x_1, 2x_(k+1)),

显然也是一一映射。接下来证明当 n=4m+2 时不存在满足要求的(乘法)群 S 以及映射 A, B, C 。

这里要用到群论的一些基本操作。S 中每个元素 g 都对应一个 S 上的置换 σ(g): x→gx,显然 σ(g1)σ(g2)=σ(g1g2) 。令 s(g) 为 σ(g) 的符号(偶置换为 1,奇置换为 -1),则 s(g1)s(g2)=s(g1g2) 。注意 s 是 S→{1, -1} 的同态,令 H 为这个同态的核,则 S/H 与 s 的值域(当然要么是 {1} 要么是 {1, -1})同构。

S 是偶数阶群,说明 S 必有二阶元 a(将 S 中每个元素跟逆元配对,显然除了单位元之外至少还有一个元素跟自己配对,它就是二阶元),这样 σ(a) 也是二阶元,可拆成若干个不相交的对换的乘积。但是 σ(a): x→ax 没有不动点(a 不是单位元),因此 σ(a) 恰好由 2m+1 个不相交对换组成,从而 s(a)=-1,s 的值域为 {1, -1}。S/H 与它同构,即 H 的大小等于 S 的一半。

上面说了一大堆,实际上就是为了得出 S 中有 2m+1 个元素满足 s(.)=1,有 2m+1 个元素满足 s(.)=-1,所有元素的 s(.) 值相乘等于 -1。注意 A(x)*B(x)=C(x) 可以推出 s(A(x))*s(B(x))=s(C(x)),让 x 将 S 中所有元素遍历一遍,得到的 n 个式子相乘,得到 (-1)*(-1)=-1,矛盾。所以无法满足题目的要求。

2017-06

此题一个非常令人惊奇的结论是:将均匀分布改为任意关于原点对称的连续分布,结果都是一样的!

首先考虑一个限定版问题:限定 Δ=(Δ_1, ... , Δ_n) 是给定数组 δ=(δ_1, ... , δ_n) 的“带符号”排列(即重排之后可以任意添加正负号),可以不妨假设从 δ 中任取若干个数进行加减运算都不为 0 。显然 δ 能取遍 R^n 中所有点,除了挖去一些超平面之外(反正这些平面总共加起来也是零测度,可以忽略)。这样 Δ 就有 2^n*n! 种不同取值(δ 中某两个分量相等的情况已经挖掉了;当然实际上取值能不能相同都无所谓了),假设这些取值概率均等。

现在请问,若让初始时位于 x_0=0 的点按照 Δ 的取值运动,则该点从未移动到负半轴(即 Δ 任取前 k 个分量求和均非负)的概率是多少?或者等价地说,Δ 的 2^n*n! 种不同取值中有多少种取值满足题目要求?

为了辅助理解,可以想象整个 R^n 空间被刚才挖去的那些超平面分成若干对称的区域,点 δ 可以在区域内部自由移动。在 δ 移动的同时,Δ 的 2^n*n! 种不同取值(对应空间中 2^n*n! 个点)也跟随运动,这些点都与 δ 有某种对称关系(就好像是 δ 的镜像一样);当 δ 跨过区域边界时,Δ 的 2^n*n! 个可能落点也同步跨过各自区域的边界。满足题目要求的点(即任取前 k 个分量求和均非负)组成的区域称为可行域,它的边界即前缀和等于 0 的边界,也属于刚才挖去的平面,因此可行域就是若干个刚才划分的区域的并集。现在只要数一下 Δ 中有多少个点落在可行域内就行了。

下面是二维的情况,其中大点为 δ ,大点小点共 8 个点都是 Δ 的落点,橙色区域表示可行域(x>0, x+y>0)。可以看到可行域内总是有 3 个点。


当然直接数也很困难,但是我们可以先证明无论 δ 怎么移动,可行域内落点个数都不变。显然只需说明 δ 刚好跨过某个区域边界的情况即可(只需考虑 δ 只跨过一个边界的情况,不用考虑同时跨多个边界的情况),举个例子说明:假设 δ 跨过了某个区域边界,使得点

Δ=(Δ_1, Δ_2, Δ_3, Δ_4, Δ_5)=(δ_2, -δ_4, -δ_1, δ_5, δ_3)

跨过了边界 Δ_1+Δ_2+Δ_3=0,从可行域离开进入不可行域。这说明 δ_2-δ_4-δ_1 的符号由正变负,且各个 δ_i 的其他所有加减组合符号都没变(因为只跨了一个边界),特别地,前缀和 δ_2,δ_2-δ_4,δ_2-δ_4-δ_1+δ_5 以及 δ_2-δ_4-δ_1+δ_5+δ_3 仍然为正数。现在考虑点

Δ'=(Δ'_1, Δ'_2, Δ'_3, Δ'_4, Δ'_5)=(δ_1, δ_4, -δ_2, δ_5, δ_3)

具体操作是“将前三个分量翻转并改变符号,后面的分量保持不动”,容易验证这个点必然从不可行域进入可行域。这样可以发现,有几个点从可行域离开,就相应有几个点进入可行域,因而可行域内落点个数始终不变。

(有人可能根据上述二维的图示认为:每个区域边界都是 Δ 点集的对称轴,即每个从可行域离开的点都对应一个从同样位置进入可行域的点。这是不对的。三维空间中,点 (x, y, z) 关于平面 x+y+z=0 的对称点是

((x-2y-2z)/3, (-2x+y-2z)/3, (-2x-2y+z)/3)

显然当 (x, y, z) 是 Δ 中一点时,对称点未必也是 Δ 中一点。)

最后我们选一个比较好算的 δ ,计算 Δ 中落在可行域内的点数。记这个数为 A_n,选取 δ=(2^0, 2^1, 2^2, ... , 2^(n-1)),它有一个极好的性质是高次幂碾压一切低次幂之和。显然去掉第一个分量 1 它就变成了 n-1 的情况,总共有 A_(n-1) 种选择;然后在其中插入 1 或 -1,只要不往开头插入 -1 就行,共有 2n-1 种插法。于是 A_n=(2n-1)*A_(n-1),累乘可得 A_n=(2n-1)!!(n=1 只有一种选择,就是 δ=(1),故初始情况 A_1=1),相应概率(即可行域内落点占全部落点总数的比值)就是


以上所有讨论说明了一点:我们划分的所有区域全部完全相同,而可行域就是其中若干区域的并集,所占比例即为 P_n 。

现在回到原问题,请注意题目中所求概率是在可行域上对 (Δ_1, ... , Δ_n) 的联合分布密度函数积分(零测度集可忽略),而联合密度函数就是简单地将各分量的密度函数自乘 n 次方,具有完全的对称性(交换两个变量或者将一个变量取相反数,值不变),因而密度函数在各个区域的积分都相等。既然密度函数在全空间积分为 1,在可行域上积分自然就是 P_n 。因此题中所求概率就是上述 P_n 的表达式。

2017-07

(1)设 A 为某个需要实现初始化操作的数组。显然初始化操作不能真的老实去修改每个变量,我们开两个变量 flag, default,其中 flag 表示数组是否进行过初始化操作(初始时 flag=0,进行一次初始化后 flag 就永远是 1 了),default 表示上一次初始化设置的值。这样问题又来了:如何判断数组中某个元素在初始化后被修改过?

显然不能再开一个长度相同的 01 数组,那样每次初始化都要将数组置零,就又回到老问题了。这时就要换一种思路,开一个变长数组 B 记录所有被改过的值的下标。具体地说,令 B 为长度与 A 相同的数组,用 length 记录该数组实际使用的长度。进行初始化只需让 length=0 即可。每次取值时看下标是否在数组 B 中,有则从数组 A 中取值,没有则取 default 的值;每次改值时修改数组 A 中的值,然后看下标是否在数组 B 中,没有则让 length 加一并把下标放到 B[length] 中。

“查找下标是否在 B 中”的操作不是常数时间的,但再开一个数组就可以把它变成常数时间:用长度与 A 相同的数组 C 记录下标在 B 中的位置,C[index] 记录下标 index 在数组 B 中的位置。注意数组 C 不需要进行初始化,因为只要 C[index] 超出区间 [1..length] 的范围,就判定 index 不在数组 B 中。维护 C 数组只需在每次向 B 中添入 index 时修改 C[index] 的值即可,当 length 归零时不需要对 C 做改动。问题宣告解决。

最后值得一提的是,在时间复杂度的假设下,可以用一个取值范围为 [0, 2^n) 的整数代替长度为 n 的 01 数组,其初始化操作以及将某处置 1 的操作均可在常数时间内实现(前者直接置为 0,后者直接与 (1<<k) 按位或),就用不着后面的这些操作了。

(2)此题便是经典的 BFPRT 线性时间求中位数算法(以 Blum, Floyd, Pratt, Rivest 和 Tarjan 五位大牛的名字命名),该算法是基于比较的算法,可以在线性时间内找出数组中第 k 顺位的数(k 为 [1, n] 内的任意整数)。

首先介绍期望 O(n) 的算法(假设 n 个数的 n! 种大小顺序概率均等):在数组中随便取一个数做主元,将小于它的数放在左边,大于它的数放在右边(等于它的数放哪边都行)。这种划分操作跟快速排序很像,但是这里不需要对两边分别递归,而是检查主元的顺位(也就是主元现在的下标,记为 m),小于 k 说明要找的是右半边第 k-m 顺位的数,大于 k 说明要找的是左半边第 k 顺位的数,等于 k 就不必再往下找了。这样只要对一边进行递归即可。用归纳法容易证明该算法确实是期望 O(n) 的。

至此离我们的要求还差了一点,因为如果每次选主元都不幸地选到了最小值,用时就变成了 O(n^2) 。解决这个问题的方法就是“中位数之中位数”方法:将数组划分为 floor(n/5) 个小组,每组有 5 个数,多余的数忽略,用插入排序找出每组的中位数,再找出 floor(n/5) 个中位数的中位数(递归)作为主元,执行上述划分操作,对左半边或右半边递归查找第 k 顺位的数。5 这个数字没有特别意义,可以改成 7 或者 9,等等。

设主元为 M,中位数之中位数算法保证了有一半小组的中位数不超过 M,这些小组中保证至少有 3 个数不超过 M,即总共有至少 3/10 的数在 M 左边,同样也有至少 3/10 的数在 M 右边。这样再进行划分操作,左右半边长度至多是原数组长度的 7/10,这一点保证了算法在最坏情况下也是线性的。(中间还多了一步就是递归找 floor(n/5) 个数的中位数,但是不影响线性复杂度)

最后注明一下,虽然两道题的算法都是可以在现实机器上实现的算法,但因为隐含的常数因子较高,实用性并不强,对第一题可以用哈希表,第二题一般用期望 O(n) 的算法(通常加个随机化,防止遭到极端数据恶意攻击)就行了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值