Googol String 问题(移位 and 推算 详解)

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;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值