HDU 1210 Eddy'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
Sample Input
20
1
Sample Output
20
2

洗牌问题:

定理1:当第一张牌(牌1)回到初始位置时,所有的牌都回到了初始位置。

证明:设有一次操作,某牌在操作前处于位置r(1<=r<=2*N),那么,操作后,如果r原来是前一半的,显然r'=r*2; 否则,r'=(r-n)*2-1,即r'='r*2-(N*2+1);
将两个式子综合,可以得到r'= (r*2)%(N*2+1);
根据同余定理之一 ((i%m)*j)%m=(i*j)%M,可以整理出公式:i次操作后,该牌的位置为:
(r*(2^i))%(N*2+1);其中^表示乘方。
现在,我们假设经过M次操作后,牌1回到了初始位置,即(1*(2^M))%(N*2+1)=1时,再次应用同余定理,可以证明对于任意的k(1<=k<=2*N),有(k*(2^M))%(N*2+1)=k,翻译成自然语言就是:当第一张牌回到初始位置时,所有的牌都回到了初始位置。命题得证。

定理2:一定存在某次操作M,这次操作后,所有的牌都回到了初始位置。
证明:我们已经证明了牌1回到初始位置时,所有的牌都回到初始位置,所以我们只需要证明牌1可以回到初始位置,即(2^M)%(N*2+1)=1一定有正整数解。证明这个定理前我们首先证明这样一个定理:
定理2.1:(2*r)%(2*n+1)==t
当t确定为1到2*n中的某值时(1<t<=2*n),r在1到2*n间有唯一解
因为2*n+1是奇数,我们只要看一下就会发现r到t是一个一一映射,当t为偶数时,显然r=t/2,当t为奇数时,r=(t+1)/2+n,

现在我们来证明定理2。运用反正法,若牌1永远不能回到初始位置,根据鸽笼定理,牌1必然陷入了某个不包含位置1的循环,因为下一状态仅和当前状态有关,当前状态最多只有2*N种,所以显然一定在不超过2*N+1次操作内出现重复状态。而重复状态则意味着循环。
因为我们假设这一循环不包括位置1,我们设f(i)为循环中某状态,f(0)=1,f(n+1)=(f(n)*2)%(2*N+1),f(j)为若干次循环后出现的重复状态,即f(i)=f(j)。因为循环一直持续,不妨假设j>i+i。又因为循环不包括状态1,即对于任意的k>=i,f(k)!=1
根据定理2.1,我们可以根据当前状态推出上一状态,换句话说,若f(i)=f(j),则f(i-1)=f(j-1)。继续套用定理2.1,可以得到f(i-i)=f(j-i),即:f(j-i)=f(0)=1。又有假设j>i+i,即j-i>i,与另一假设对于任意的k>=i,f(k)!=1矛盾。
因此,可以证明,牌1所陷入的循环,必然是包含位置1的,即一定有某次操作,操作后牌1回到了初始状态。而且显然的,初始状态就是这循环中的一个状态。
因此命题得证。

code:

View Code
 #include<stdio.h>
int main()
{
int n,sum,k;
while(scanf("%d",&n)!=EOF)
{
sum=0;
k=1;
for(;;)
{
if(k>n)
k=2*(k-n)-1;
else
k=2*k;
sum++;
if(k==1)
break;
}
printf("%d\n",sum);
}
return 0;
}


posted @ 2012-03-16 17:16  'wind  阅读(538)  评论(0编辑  收藏  举报