Sicily 1214. 信号分析

题目链接在此


(1)数列找规律。就是把序号写成二进制(无前导0),再倒过来就能得到对应的值。

1(1) = 1; 2(10) = 1;  3(11) = 3;  4(100) = 1 

5(101)=5; 6(110)= 3;  7(111)= 7;  8(1000)= 1; 


(2)题目要你求的就是在某数之前,其二进制恰好为回文串的数的总数。例如5的二进制是101,是回文串,所以a5=5符合条件。


(3)本题一共10个test case。觉得遍历然后判断是否为回文串的方法会超时,所以用构造回文串的方法解决。进一步找规律可以发现:

不包括0在内,

二进制为1位的,共2^0=1个回文串,即1;

二进制为2位的,共2^0=1个回文串,即11;

二进制为3位的,共2^1=2个回文串,即101和111;

二进制为4位的,共2^1=2个回文串,即1001和1111;

二进制为5位的,共2^2=4个回文串,即10001,10101,11011,11111;
二进制为6位的,共2^2=4个回文串,即100001,101101,110011,111111;

……


二进制为n位的,共2^[(n+1)/2-1]个回文串。


(4)以下以十进制数48为例找出答案:

【1】48的二进制是110000;

【2】他的二进制有6位,是【偶数】个,后文还会介绍奇数位情况的数

【3】在48之前的二进制为1-5位且为回文串的数共1+1+2+2+4=10个

【4】再看在他之前的二进制为6位的数。看最高的(6/2=3)位:110。比110小且以1开头的二进制数有

100,101这2个。这四个可以直接”对称“到右边形成回文串100001,101101。比110小这“2”个是怎么数出来的来的呢?110有3位,除去前面的1,得到10,即为十进制的2,也就是说比110小的有2个。这样一来,目前就有10+2=12个符合要求的回文串。

【5】最后再看110000本身,他的前(6/2=3)位:110,本身能否构造一个符合要求的回文串呢?如果能,就是110011,发现他比110000要大,所以不行。怎么判断的呢?看他左半边110的倒置011是否小于或等于右半边000即可。

【6】于是一共有12个符合要求的回文串。搞定。


(5)以下以十进制数100为例找出答案:

【1】100的二进制是1100100;

【2】他的二进制有7位,是【奇数】个。

【3】在100之前的二进制为1-6位且为回文串的数共1+1+2+2+4+4=14个

【4】再看在他之前的二进制为7位的数。看最高的(7/2+1=4)位:1100。比1100小且以1开头的二进制数有

1000,1001,1010,1011这4个。这四个可以以最末位为轴”对称“到右边形成回文串1000001,1001001,1010101,1011101。比1100小这“4”个是怎么数出来的来的呢?1100有4位,除去前面的1,得到100,即为十进制的4,也就是说比1100小的有4个。这样一来,目前就有14+4=18个符合要求的回文串。

【5】最后再看1100100本身,他最高的前(7/2+1=4)位:1100,本身能否构造一个符合要求的回文串呢?如果能,就是1100011,发现他比1100100要小,所以可以。怎么判断的呢?看他左半边110的倒置011是否小于等于右半边100即可。

【6】于是一共有18+1=19个符合要求的回文串。搞定。


(6)最后注意数据规模问题,要用long long型。


以下代码就是以上述过程为思路写的,具体就不写什么注释了。写了一晚上一早上,最后AC了还是很有成就感的。


#include<stdio.h>
#include<math.h>
#pragma warning(disable:4996)  //  屏蔽VS对scanf报错

using namespace std;

int main() {
	long long limit;
	scanf("%lld", &limit);

	long long palindromeNum = 0;
	int digit = 1;  //  数这个数二进制有多少位

	while ((long long)pow(2.0, digit) <= limit) {
		digit++;
	}

	for (int i = 1; i < digit;i++) {
		palindromeNum += (long long)pow(2.0, (i + 1) / 2 - 1);
	}

	int half = digit / 2;
	long long highHalf = limit / (long long)pow(2.0, half);

	if (digit % 2 == 0)
		palindromeNum += highHalf - (long long)pow(2.0, half - 1);
	else if (digit % 2 == 1)
		palindromeNum += highHalf - (long long)pow(2.0, half);

	int bits[64];
	int count = 0;
	while (limit != 0) {
		bits[count++] = limit % 2;
		limit /= 2;
	}

	bool isGtEq = true;  //  是否大于或等于
	for (int i = half-1; i >=0; i--) {  //  将【低半部分】与【倒置的高半部分】比,从高位比到低位
		if (bits[i] > bits[digit - 1 - i]) {
			break;
		}
		else if (bits[i] < bits[digit - 1 - i]) {
			isGtEq = false;
			break;
		}
	}
	if (isGtEq)
		palindromeNum += 1;

	printf("%lld\n",palindromeNum);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值