标签:sicily
Time Limit: 1 secs, Memory Limit: 32 MB
Hanoi Tower is a famous game invented by the French mathematician Edourard Lucas in 1883. We are given a tower of n disks, initially stacked in decreasing size on one of three pegs. The objective is to transfer the entire tower to one of the other pegs, moving only one disk at a time and never moving a larger one onto a smaller.
The best way to tackle this problem is well known: We first transfer the n-1 smallest to a different peg (by recursion), then move the largest, and finally transfer the n-1 smallest back onto the largest. For example, Fig 1 shows the steps of moving 3 disks
from peg 1 to peg 3.
Now we can get a sequence which consists of the red numbers of Fig 1: 1, 2, 1, 3, 1, 2, 1. The ith element of the sequence means the label of the disk that is moved in the ith step. When n = 4, we get a longer sequence: 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1,
2, 1. Obviously, the larger n is, the longer this sequence will be.
Given an integer p, your task is to find out the pth element of this sequence.
The first line of the input file is T, the number of test cases.
Each test case contains one integer p (1<=p<10^100).
Output the pth element of the sequence in a single line. See the sample for the output format.
Print a blank line between the test cases.
4 1 4 100 100000000000000
Case 1: 1 Case 2: 3 Case 3: 3 Case 4: 15
ZSUACM Team Member
这份是自己做的,用时0.02s:
#include <stdio.h> #include <string.h> //通过观察规律可知,位置k上的数就是k可以被而整除的次数+1 int ac[110] = {0};//用来高精度除以低精度的 bool is_ok;//判断是否可以进行下一次除以2 int divi(int first_pos, int length) { for (int i = first_pos; i < length; i++) {//高精度除以低精度 if (ac[i] > 0) { if (ac[i] % 2 == 1) { ac[i + 1] += 10; } ac[i] /= 2; } } if (ac[length] > 0) {//假如length位置上有了大于零的(ac[i + 1] += 10;)说明length-1这一位出现了单数,已经不能整除了 is_ok = false; return 0; } if (ac[first_pos] == 0)//更新数字长度 return first_pos + 1; else return first_pos; } int main() { int t, i, length, counter, kongzhi = 0, first_pos, j; scanf("%d", &t); for (i = 1; i <= t; i++) { char a[105] = {'\0'}; is_ok = true; memset(ac, 0, sizeof(ac)); scanf("%s", a); length = strlen(a); if (kongzhi)//输出的格式 printf("\n"); kongzhi = 1; if ((a[length - 1] - '0') % 2 == 1) {//假如是单数直接判断 printf("Case %d: 1\n", i, 1); continue; } counter = 0; if (length <= 20) {//假如小于unsigned long long的最大值18446744073709551615直接判断 char judge[] = "18446744073709551615"; if (strcmp(a, judge) <= 0 || length <= 19) { unsigned long long sum = 0; for (j = 0; j < length; j++) { sum = sum * 10 + a[j] - '0' ; } while (sum % 2 == 0) { counter++; sum /= 2; } printf("Case %d: %d\n", i, counter + 1); continue; } } for (j = 0; j < length; j++) { ac[j] = a[j] - '0'; } first_pos = 0; while (1) {//进行高精度除以低精度 first_pos = divi(first_pos, length); if (is_ok) counter++; else break; } printf("Case %d: %d\n", i, counter + 1); } return 0; }后来用了10^9的基数的数组提高效率,这次是0s:
#include <stdio.h> #include <string.h> #include <math.h> #define MAX_LENGTH 105 //这里用的是基数为10的9储存方式,提高效率 int base_index = 9;//基数为10的9次方 long long unit_base = (long long)pow(10, 9);//基数大小 long long unit[MAX_LENGTH / 9 + 9];//基数为10^9的最大长度数组 long long per_base[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};//构建unit数组用到的 char char_a[MAX_LENGTH]; bool is_ok;//判断是否要进行下一次除以2 int ready(int length) { memset(unit, 0, sizeof(unit)); int unit_length = length % 9 == 0 ? length / 9 : length / 9 + 1;//计算所需unit长度 int i, j, k; for (i = unit_length - 1, j = length - 1; i >= 0; i--) {//注意一定要从末尾开始构建 for (k = 0; j >= 0; j--, k++) { if (k == 9)//每9位数更新一个跳到前一个unit下标 break; unit[i] += (char_a[j] - '0') * per_base[k]; } } return unit_length; } int divi(int first_pos, int last_pos) { if (unit[last_pos] % 2 == 1) {//假如假如末尾是单数直接不能继续除以2 is_ok = false; return 0; } for (int i = first_pos; i <= last_pos; i++) {//高精度除法 if (unit[i] % 2 == 1) { unit[i + 1] += unit_base; } unit[i] /= 2; } if (unit[first_pos] == 0)//更新unit数组的首位 return first_pos + 1; else return first_pos; } int main() { int t, i, length, counter, kongzhi = 0, first_pos, j; scanf("%d", &t); for (i = 1; i <= t; i++) { if (kongzhi)//输出的格式 printf("\n"); kongzhi = 1; memset(char_a, '\0', sizeof(char_a)); scanf("%s", char_a); length = strlen(char_a); is_ok = true; if ((char_a[length - 1] - '0') % 2 == 1) {//假如是单数直接判断 printf("Case %d: 1\n", i, 1); continue; } counter = 0; if (length <= 20) {//假如小于unsigned long long的最大值18446744073709551615直接判断 char judge[] = "18446744073709551615"; if (strcmp(char_a, judge) <= 0 || length <= 19) { unsigned long long sum = 0; for (j = 0; j < length; j++) { sum = sum * 10 + char_a[j] - '0' ; } while (sum % 2 == 0) { counter++; sum /= 2; } printf("Case %d: %d\n", i, counter + 1); continue; } } int unit_length = ready(length); first_pos = 0; while (1) { first_pos = divi(first_pos, unit_length - 1);//不断高精度除以2 if (is_ok) { counter++; } else { break; } } printf("Case %d: %d\n", i, counter + 1); } return 0; }
Sicily 1028. Hanoi Tower Sequence
标签:sicily
原文地址:http://blog.csdn.net/u012925008/article/details/44763419