洗牌问题

题目大意:

设 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??你他妈考我RP啊。。求大神解释!!!!!网络上一群傻逼的题解都是说 “因为移动的规则相同,那么只要任意一个数回到了原位,其他数也回到了原位",那么就愉快的取了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)); 

时间: 2024-10-11 12:44:03

洗牌问题的相关文章

[转]完美洗牌(Perfect Shuffle)问题

[转]原博文地址:https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/zh/02.09.md 完美洗牌算法 题目详情 有个长度为2n的数组{a1,a2,a3,...,an,b1,b2,b3,...,bn},希望排序后{a1,b1,a2,b2,....,an,bn},请考虑有无时间复杂度o(n),空间复杂度0(1)的解法. 题目来源:此题是去年2013年UC的校招笔试题,看似简单,按照题目所要

4月6日--关于算法数的练习题--扑克洗牌

扑克 1.定义一个数组,存放1-52(分别表示52张扑克,不含大.小王)其中1表示黑桃A,2表示黑桃2...,13表示 黑桃K,14表示红桃A......) 2.随机排列该数组 3.再将牌平均分给4个玩家(分成4个数组,按照发牌规则) 4.排序输出每个玩家的扑克(先按照花色:黑桃.红桃.梅花,方块;再按照大小) <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&q

2017联合办公洗牌关键词:生存、扩张、盈利、因地制宜_转

转自:http://www.iheima.com/zixun/2017/0206/161059.shtml "大众创业,万众创新",不只催生了千军万马的创新创业者,更衍生出联合办公这样独特的办公模式.这一办公模式从无到有,从最初单一的复制借鉴到今天品类繁多的百花齐放,已经进化成对创业者有着致命吸引力的办公地址选择. 粗略统计,截至2016年初,中国联合办公空间数量已经超过2300家. 福兮祸所依,在各式各样的联合办公野蛮生长的背后,可以预见的是市场优胜劣汰的残酷洗牌. 未来联合办公的发

hdu 1210 Eddy&#39;s 洗牌问题

Problem Description Eddy是个ACMer,他不仅喜欢做ACM题,而且对于纸牌也有一定的研究,他在无聊时研究发现,如果他有2N张牌,编号为1,2,3..n,n+1,..2n.这也是最初的牌的顺序.通过一次洗牌可以把牌的序列变为n+1,1,n+2,2,n+3,3,n+4,4..2n,n.那么可以证明,对于任意自然数N,都可以在经过M次洗牌后第一次重新得到初始的顺序.编程对于小于100000的自然数N,求出M的值. Input 每行一个整数N Output 输出与之对应的M Sa

java语言实现简单的洗牌,发牌

java学习过程中,老师让写了个简单的斗地主洗牌发牌的程序,一下就是程序代码: package com.java.lei.homework; import java.util.Arrays; import java.util.Random; public class PokerGame { //1.创建数组,用以存储扑克牌 static String[] pokers = new String[54]; public static void main(String[] args) { //2.创

算法之洗牌算法

洗牌算法是我们常见的随机问题,在玩游戏.随机排序时经常会碰到,一个最常用的地方就是组卷.它可以抽象成这样:M以内的所有自然数的随机顺序数组. package com.math; import java.util.Random; /** * @author summer * */ public class Shuffle { static final int[] a = new int[54]; static Random rnd = new Random(); static{ for(int i

(算法)完美洗牌

题目: 编写一个方法,洗一副牌,要求做到完美洗牌,即这副牌52!中排列组合出现的概率相同. 思路: 1.递归 2.循环 代码: #include<iostream> #include<stdlib.h> #include<time.h> using namespace std; int rnd(int lower,int higher){ return rand()%(higher-lower+1)+lower; } void shuffle_1(int *cards,

1965: [Ahoi2005]SHUFFLE 洗牌

1965: [Ahoi2005]SHUFFLE 洗牌 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 408  Solved: 240[Submit][Status][Discuss] Description 为了表彰小联为Samuel星球的探险所做出的贡献,小联被邀请参加Samuel星球近距离载人探险活动. 由于Samuel星球相当遥远,科学家们要在飞船中度过相当长的一段时间,小联提议用扑克牌打发长途旅行中的无聊时间.玩了几局之后,大家觉得单纯玩扑克

bzoj1965 [Ahoi2005]SHUFFLE 洗牌

Description 为了表彰小联为Samuel星球的探险所做出的贡献,小联被邀请参加Samuel星球近距离载人探险活动. 由于Samuel星球相当遥远,科学家们要在飞船中度过相当长的一段时间,小联提议用扑克牌打发长途旅行中的无聊时间.玩了几局之后,大家觉得单纯玩扑克牌对于像他们这样的高智商人才来说太简单了.有人提出了扑克牌的一种新的玩法. 对于扑克牌的一次洗牌是这样定义的,将一叠N(N为偶数)张扑克牌平均分成上下两叠,取下面一叠的第一张作为新的一叠的第一张,然后取上面一叠的第一张作为新的一叠

完美洗牌算饭

被大腾讯问到了完美洗牌算法,瞬间就跪了,其实原来看过,只可惜都忘了啊,现在在补充进来吧. 其实完美洗牌算法,应该给我说明白题,最少举个例子吧,当时确实大意了,也没问清楚就直接不会了,其实题意是有个长度为2n的数组{a1,a2,a3,a4,..,an,b1,b2,b3,b4,...,bn},希望排序后{a1,b1,a2,b2,...,an,bn},最好要求时间复杂度为O(n),空间复杂度为O(1). 解法一:蛮力交换方法 1.1 说白了就是b1和a2,a3,a4,...,an交换,然后是b2和a3