Problem
A "0/1 string" is a string in which every character is either 0 or 1. There are two operations that can be performed on a 0/1 string:
switch: Every 0 becomes 1 and every 1 becomes 0. For example, "100" becomes "011".
reverse: The string is reversed. For example, "100" becomes "001".
Consider this infinite sequence of 0/1 strings:
S[0] = ""
S[1] = "0"
S[2] = "001"
S[3] = "0010011"
S[4] = "001001100011011"
...
S[N] = S[N-1] + "0" + switch(reverse(S[N-1])).
You need to figure out the Kth character of Sgoogol, where googol = 10^100.
Input
The first line of the input gives the number of test cases, T. Each of the next T lines contains a number K.
Output
For each test case, output one line containing "Case #x: y", where x is the test case number (starting from 1) and y is the Kth character of Sgoogol.
Limits:1 ≤ T ≤ 100.
Small dataset:1 ≤ K ≤ 105.
Large dataset:1 ≤ K ≤ 1018.
in:
5
1 2 3 10 12
put:
case 1:0
case 2:0
case 3:1
case 4:0
case 5:1
题目解读 :
Googol = 10^100:
题目要求输入k,求S[Googol]字符串的第k个字符。
由于Googol已经超出了数值型数据的表示范围,而K却最大10^18(小于long long 类型的上限),也就是说我们可以表示出k而不能表示Googol。但我们所求的S[Googol]字符串的第k个字符不一定要得到S[Googol]。
比如我求第1个字符(假设用S[i][j],表示第i+1个字符串的第j+1个字符)S[1][0]是0,S[10][0]也是0,S[无穷][0]也只会是0
因此,我们求第k个元素,只要在长度刚好大于k的那个字符串中找
而长度又有如下关系:
S[0].len= 0
S[1].len = 1
S[2].len = 3
S[3].len = 7
S[4].len = 15
...
S[N].len = pow(2,N)-1;
因为 k<=S[N].len = pow(2,N)-1;
已知k求N
N > log2(k+1),由于N是整数,那么只需对log2(k+1)向上取整就是我们要找的值
递归:
#include<stdio.h>
#include<math.h>
int find(long long i, long long k) { //i表示字符串Si,k表示第k个字符,也就是在Si字符串中找第k个字符
long long mid = ((long long)1 << (i - 1));
if (k == mid) //如果在中间说明为0
return 0;
else if (k < mid) //如果在左边说明跟上一字符串的同一位置相同
return find(i - 1, k);
else
return !find(i - 1, (mid << 1) - k); //右边的话就是上一字符串对称位置的反转
}
int main() {
int n;
long long max, k;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%lld", &k);
max = ceill(log2l(k + 1)); //最多只需要在第log2(k)个字符中查找字符k(注意向上取整以及数据类型)
printf("case %d:%d\n", i, find(max, k));
}
return 0;
}
迭代:
#include<stdio.h>
#include<math.h>
int find(long long x, long long k) {
int t = 0;
while (true) {
long long mid = ((long long)1 << (x - 1)); //注意此处的数据类型
if (k == mid)
return t;
else if (k > mid) { //如果在右侧,折半取反
t = !t;
k = (mid << 1) - k;
}
x--;
}
}
int main() {
int n;
long long max, k;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%lld", &k);
max = ceill(log2l(k + 1)); //最多只需要在第log2(k)个字符中查找字符k(注意向上取整以及数据类型)
printf("case %d:%d\n", i, find(max, k));
}
return 0;
}