HDOJ 1210 Eddy的洗牌问题 题解

来源:互联网 发布:数据字段进行etl拆分 编辑:程序博客网 时间:2024/06/06 15:37

一开始傻乎乎地模拟洗牌过程,果然超时了。

得想办法找出规律,“走捷径”。

下标变换的规律

设初始下标为i(i=1,2,3,...,2N),有两种情况:

  1. next(i) = i * 2, 当 i 属于 [1,N]时;
  2. next(i) = (i - N - 1) * 2 + 1, 当i属于[N+1, 2N]时。

对第二种情况的解释为后半部分中且位于i之前的下标变换后依次跟着前半部分的一个下标,所以占去了新下标前面(i-N-1)*2个位置,因此i在变换后的位置为(i-N-1)*2+1;

循环周期与最小公共循环周期

题目说,对于任意自然数N,都可以在经过M次洗牌后第一次重新得到初始的顺序。那么,可以知道,针对初始下标为i的元素,其下标变换的最小周期小于等于M。或者说,M是初始下标为i的元素的下标变换最小周期的正整数倍。
举例来说,n=4时,下标为1的元素的下标变换循环为:
1-2-4-8-7-5-1,

可知初始下标分别为 1,2,4,5,7,8的元素的最小变换周期是6。
而上面没有出现过的初始下标3,其变换循环为:
3-6-3,

可知初始下标分别为3,6的元素下标变换周期为2.

找到这里,我们发现所有的初始下标的最小变换周期都被我们找出来了,那么,所求M为lcm(6,2) = 6.

分析到这里,已经可以解决本题了。

接下来我们来看看mod运算对此的优化。

使用取模运算合并分情况讨论

利用取模运算可以将分情况讨论合并成统一的表达式!
 因为下标范围是 [1, 2N],所以  i = i mod (2N + 1)恒成立。
当i属于 [1, N]时:
next(i) = i * 2 = (i * 2) mod (2N + 1);
当i属于 [N+1, 2N]时:
next(i) = (i-N-1)*2+1 = i*2 -2N - 2 + 1 = i*2-2N - 1 = (i * 2 - (2N + 1)) mod (2N + 1) = (i * 2) mod (2N + 1);
因此将两种情况合并,得:
next(i) = (i * 2) mod (2N + 1),其中i属于[1, 2N]。

1的最小变换周期是所有下标的最小变换周期的最小公倍数

依据模运算的性质,既可以在每一步都进行取模运算,又可以在运算完毕后进行取模运算。

我们设下标i在经过p步之后的下标为next(i, p):
next(i, p) =...((( i * 2) mod(2N+1)) * 2) mod (2N+1))...(重复p次) =  (i * pow(2, p)) mod (2N + 1).

假设下标1经过Q步第一次变回了1,那么有:
next(1, Q) = (1 * pow(2, Q)) mod (2N + 1) = 1,
即 pow(2, Q) mod (2N + 1) = 1,
有没有可能任意其他下标经过Q步,都能回到原来位置呢?
也就是 next(i, Q) = i, 其中 i 属于 [1, 2N], 即 (i * pow(2, Q)) mod (2N + 1) = i成立呢?
根据前面的假设,因为有pow(2, Q) mod (2N + 1) = 1, 并且 i < (2N + 1),所以(i * pow(2, Q)) mod (2N + 1) = i 成立的。
所以只需求取初始下标为1的元素的最小循环周期,即得答案。

0 0
原创粉丝点击