题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1210
模拟的题目真不知道怎么写的话,就把真实情况展示出来,有图才有真相:
测试代码:


#include <iostream> using namespace std; int main() { int N; cin >> N; int *a = new int[2 * N + 1]; int *b = new int[2 * N + 1]; for (int i = 0; i <= 2 * N; i++) { a[i] = i; } for (int i = 1; i <= 2 * N; i++) { b[(i * 2) % (2 * N + 1)] = a[i]; } for (int i = 1; i <= 2 * N; i++) { cout << b[i] << " "; } cout << endl; for (int i = 1; i <= 2 * N; i++) { a[(i * 2) % (2 * N + 1)] = b[i]; } for (int i = 1; i <= 2 * N; i++) { cout << a[i] << " "; } cout << endl; for (int k = 0; a[1]!=1&&b[1]!=1; k++) { if (!(k & 1)) { for (int i = 1; i <= 2 * N; i++) { b[(i * 2) % (2 * N + 1)] = a[i]; } for (int i = 1; i <= 2 * N; i++) { cout << b[i] << " "; } cout << endl; } else { for (int i = 1; i <= 2 * N; i++) { a[(i * 2) % (2 * N + 1)] = b[i]; } for (int i = 1; i <= 2 * N; i++) { cout << a[i] << " "; } cout << endl; } } return 0; }
我们先假设N=4时,画个图看一下变化情况:
蓝色:1→2→4→8→7→5→1:六步
橙色:3→6→3 :两步
我们可以想象一下,每次将牌分成两半,不停的进行依次归并,直到所有牌回到正确位置(而且,不论哪种排列1都是最长的循环之一)。
当前位置是i,下一次位置是:
正向(位置上1,2,4,8):i * 2
反向(也可以看成1,2,4,8):(i - n) * 2 - 1 = 2 * i - 2 * n - 1(n是4,不是8,别弄错了)
结论:每次把在第i个位置的数移动到位置 i * 2 % (2 * N+1) 的位置上。
完整代码(%运算要比简单乘除慢很多,还是选择分开了,虽然代码长了一点):
#include <iostream> #include <stdio.h> using namespace std; int main() { int n; while (~scanf("%d",&n)) { int i = 2, res = 1; if (n != 0) while (i != 1) { i <<= 1; if (i > 2 * n) i = i - 2 * n - 1; res++; } cout << res << endl; } return 0; }