题目链接在此
(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;
}