• 洗牌问题


    题目大意:

    设 2n 张牌分别标记为 1, 2, ..., n, n+1, ..., 2n,初始时这 2n 张牌按其标号从小到大
    排列。经一次洗牌后,原来的排列顺序变成 n+1, 1, n+2, 2, ..., 2n, n。即前 n 张牌被放到
    偶数位置 2, 4, ..., 2n,而后 n 张牌被放到奇数位置 1, 3, ..., 2n-1。可以证明对于任何一
    个自然数 n,经过若干次洗牌后可恢复初始状态。现在你的的任务是计算对于给定的 n 的值(n≤10^5 ),
    最少需要经过多少次洗牌可恢复到初始状态。

     

    解题过程:

    1.模拟绝对超时,然后就开始找规律,对于当前位置是x的数,如果x<=n,下一次就会跑到2*x的位置。否则会跑到(2*x-1) mod (2*n)的位置。

    2.手工模拟了下,感觉只要一个数回到原位其他数也就回来了,那么取位置1,按照规则不断模拟,知道回到1为止,然后就糊里糊涂AC了。

    3.考后怎么也想不明白为什么只要任意取一个数就好,结果TMD 找到了一个反例:n=10的时候;

    如果一开始取位置1的数,那么它的位置变化是 1->2->4->8->16->11->1  那么答案就是6。

    如果一开始取位置3的数,那么它的位置变化是 3->6->12->3->6->12->3

    可以发现第3次洗牌后,位置3的数回到了原位,但是位置1的数还没有,如果一开始选了位置3的数,那么答案就会是3。

    难道只要一开始选位置1的数就能AC??

    http://tieba.baidu.com/p/3246473319 贴吧大神给了解释。 祝热心的大神rp++。

    首先一个位置为x的数,变换一次后,位置变成了 (2*x) mod (2*n+1);

    如果初始位置为x的数变换t次后回到原位,那么 有 x * 2^t ≡ x (mod (2n+1)) 下面的证明需要一些同余式的知识。

    A:  如果gcd(x,2n+1)= 1 , 则有  2^t1 ≡ 1  ( mod (2n+1) ) 

    B: 如果gcd(x, 2n+1)> 1 ,  则有  2^t2 ≡ 1  ( mod (2n+1)/gcd(x,2n+1) );

    可以证明 t1 必定是 t2 的倍数,证明如下:(t1,t2都是符合要求的最小的那个)

    设 t1=a*t2 + b (0<=b<t2)   ,  (2n+1)/gcd(x,2n+1)=m

    A: 2^t2 ≡ 1 (mod m)  -> 2^(a*t2) ≡ 1 (mod m) 

    B: 2^t1 ≡ 1 (mod (2n+1)) ->  2^(a*t2 + b) ≡ 1 (mod (2n+1)) ->   2^(a*t2 + b) ≡ 1 (mod m)  (因为2n+1是m的倍数);

    根据 A,B 可以得到 2^b ≡ 1 (mod m)  ,而 b < t2 因此b=0,否则与前面 “t1,t2都是符合要求的最小的那个”矛盾,因此b=0; 所以 t1= a * t2 , 即 t1 是 t2 的倍数;

     而我们要求的最终答案是 所以 t 的最小公倍数 , 因此 x 与 2n+1 互质的时候取得t就是答案,这也就解释了上面为什么取1 就能得到答案 而取 3 就挂掉了。

     求解答案只要求 2^t ≡ 1 (mod 2n+1)  的最小解;

    首先 phi(2n+1) 是 满足条件的。

    那么答案 必定是 2n+1 的约数, 证明 同上 ,把ans看成 t2, 把 phi(2n+1)看成 t1, 那么同理 t1=a*t2 ;

    所以 只要 枚举 phi(2n+1)的约数,用快速幂判断是否符合即可。

    复杂度进一步从O(ans) 降到了 O(sqrt(n)*log(n)); 

    另外如果只要证明为什么1回到原位,那么所有数都回到原位的话,有个很简单的证明,  设1 经过t次回到 原位 ,那么 2^t ≡ 1 (mod (2n+1)); 两边同时乘一个x,那么有2^t * x ≡ x (mod (2n+1)) ,也就是 其他数也 回到了原位。

     

  • 相关阅读:
    五大Java开源论坛
    mysql limit,offset 区别
    查询某个字段存在于哪几个表
    C++分享笔记:5X5单词字谜游戏设计
    Linux分享笔记:系统状态检测命令小结
    Linux分享笔记:查看帮助命令 & 常用系统工作命令
    数据结构(C语言)分享笔记:数据结构的逻辑层次、存储层次
    Linux分享笔记:shell终端的介绍
    Java开发学生管理系统
    JAVA使用JDBC连接,修改MySQL数据库(比较乱)
  • 原文地址:https://www.cnblogs.com/vb4896/p/3929353.html
Copyright © 2020-2023  润新知