杂:某三道依赖数组长度为 2^{k} 的杂题

问题 1:

给定序列 \(a_0, a_1, a_2, \cdots, a_n\) 满足 \(n - 1 = 2^{k} (k \geq 0)\) 。定义 \(R_{i}\)\(i\)\(k\) 位的无符号二进制反转。

输出 \(a_{R_{0}}, a_{R_{1}}, a_{R_{2}}, \cdots, a_{R_{n - 1}}\)

题解:

首先考虑如何得到 \(R_{i}\) 。对二进制下标使用微扰法,注意到:

\[\begin{aligned} &\lfloor \frac{ R_{\lfloor \frac{i}{2}} \rfloor }{2} \rfloor = R_{i} \odot (2^{n - 1} - 1) \\ \Rightarrow &R_{i} = \lfloor \frac{ R_{\lfloor \frac{i}{2}} \rfloor }{2} \rfloor | ( (i \odot 1) \times 2^{n - 1} ) \end{aligned} \]

其次考虑如何让 \(a_0, a_1, a_2, \cdots, a_{n - 1}\) 变成 \(a_{R_{0}}, a_{R_{1}}, a_{R_{2}}, \cdots, a_{R_{n - 1}}\) 。注意到序列分解成了 \(\frac{n - 1}{2}\) 个循环群,每个群为 \((i, R_{i})\) ,只需循环移位一次。\(for \ i \ = 0 \to \frac{n - 1}{2}\) \(swap(a[i], a[R[i]])\) 即实现。

问题 2:

考虑对 \(0, 1, 2, \cdots, n\) 满足 \(n - 1 = 2^{k} (k \geq 0)\) 的数轴二分分治。对分治的每个区间 \(l, r\) 需要使用指针 \(i, j\) 分别指向起点和中点开始并行右移。做出非递归版本的代码实现。

题解:

代码实现如下。

for (int m = 2; m < n; m *= 2) {
	for (int l = 0; l + m - 1 < n; l += m) {
		for (int i = l, j = l + m / 2; i < l + m / 2; i++, j++) {
			
		}
	}
}
  1. 问题的关键在于先考虑从小到大枚举区间长度。从最小非叶子区间长度 \(m = 2\) ,枚举到根的区间长度 \(n - 1\) ,每次区间长度会乘以 \(2\)
  2. 其次在于枚举每个区间的左端点 \(l\) ,下一个区间的端点为 \(l + m\) ,需要保证右端点不超过 \(n - 1\)\(l + m - 1 < n\)
  3. 最后是对每个区间操作,显然不难是并行指针 \(i, j\) 分别指向 \(l\) 和中点 \(l + m / 2\) ,保证左指针不超过中点或右指针不超过右端点即可。
posted @ 2024-09-29 14:01  zsxuan  阅读(5)  评论(0编辑  收藏  举报