因为考试所以最近都没有做什么题。想不到这题都卡(~~~~(>_<)~~~~ ),看来太久没有做题感觉变迟钝了,当然也有原因是找规律的题做得比较少,所以就这样了,看来要快快调整好,好好努力才行。
先上题目
Eddy's 洗牌问题
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 2602 Accepted Submission(s): 1718
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->2->4···这样变化,后来还是不得不上网看了一下题解,发现只需要判断1有没有回到一开始的位置就可以了,1的变化就是一开始是1->2->4```这样变化,但是当去到后面到达不了2的n次幂的情况下,就要按照题目的方法把1放回到前面,位置在(i-n)*2-1,其中i是1的当前位置,n是输入的n,i要大于n且i*2也要大于2*n才执行这一步。
上代码
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #define MAX 10000 5 6 using namespace std; 7 /* 8 typedef struct 9 { 10 int d[MAX]; 11 }D; 12 13 D s; 14 15 void loadlist(D u,int m) 16 { 17 int i; 18 for(i=1;i<=m;i++) printf("%d ",u.d[i]); 19 printf(" "); 20 } 21 22 bool check(D u,int m) 23 { 24 int i; 25 for(i=1;i<=m;i++) if(u.d[i]!=s.d[i]) return 0; 26 return 1; 27 } 28 29 void deal(int n) 30 { 31 int i,j,m,count; 32 D u,v; 33 m=n*2; 34 count=0; 35 u=s; 36 loadlist(u,m); 37 while(!count || !check(u,m)) 38 { 39 for(j=2,i=1;j<=m;j+=2,i++) v.d[j]=u.d[i]; 40 for(j=1;j<=m;j+=2,i++) v.d[j]=u.d[i]; 41 u=v; 42 count++; 43 loadlist(u,m); 44 } 45 printf("%4d %4d %4d ",n,m,count); 46 } 47 48 int main() 49 { 50 int n,i; 51 char o; 52 n=0; 53 freopen("data.txt","w",stdout); 54 while(n<=100) 55 { 56 //(o=getchar())!=EOF 57 n++; 58 for(i=1;i<=2*n;i++) s.d[i]=i; 59 deal(n); 60 } 61 return 0; 62 } 63 */ 64 65 int main() 66 { 67 int i,n,m,count; 68 while(scanf("%d",&n)!=EOF) 69 { 70 i=1; 71 m=2*n; 72 count=0; 73 while(!count || i!=1) 74 { 75 if(i*2>m && i>n) 76 { 77 i-=n; 78 i=i*2-1; 79 } 80 else i*=2; 81 count++; 82 } 83 printf("%d ",count); 84 } 85 return 0; 86 }
其中前面的代码用来直接模拟得到每一步的序列,同时有最后的移动步数。真正需要提交的代码只有一小段。