讨厌110
题目
样例输入
3
4
样例输出
4 5 7
8 9 10 11 15
思路
则五位的二进制的范围是 2 n − 1 2^n-1 2n−1~ 2 n − 1 2^{n-1} 2n−1
假设n=5
范围就是16(10000)~31(11111)
那么就从16开始,从16(10000)的二进制的最右边的一位开始,验证从这一位(包含)开始往左两位这三位是否是110
16(10000) | 1 | 0 | 0 | 0 | 0 |
---|---|---|---|---|---|
第一次检验 | 0 | 0 | 0 | ||
第二次检验 | 0 | 0 | 0 | ||
第三次检验 | 1 | 0 | 0 |
一共检验n-2次
那么我们就可以用一下的代码实现这个三位检验的操作:
//time记录检验次数,cont检验这三位是否符合110,每符合一位,cont++
int time = 0, cont;
//temp存的是要检验的这个数
while (time < x - 2) {
cont = 0;
//1的二进制为001 (这里我为了方便,用三位的二进制表示),检测
//最右边的第一位是否为0
if ((temp & 1) == 0)
cont++;
//2的二进制为010
//检测右边第二位是否为1
if ((temp & 2) == 2)
cont++;
//4的二进制为100
//检测右边第三位是否为1
if ((temp & 4) == 4)
cont++;
//如果cont等于3,那么就含有110,跳过此数进行下一个数的检验
if (cont == 3)
break;
//使要检验的这个数右移
temp = temp >> 1;
//检验次数+1
time++;
}
经过这个循环检验当前数,然后就可以根据time的次数判断这个数是否含有110了
完整代码(C/C++)
#include <iostream>
#include <cmath>
using namespace std;
void No110(int x) {
int max = pow(2, x) - 1, min = pow(2, x - 1);
int temp, time,cont;
//从min到max一个个检验
while (min <= max) {
//根据规律发现在max前的那个数一定含有110
if (max - min == 1) {
cout << max << endl;
break;
}
temp = min;
time = 0;
while (time < x - 2) {
cont = 0;
if ((temp & 1) == 0)
cont++;
if ((temp & 2) == 2)
cont++;
if ((temp & 4) == 4)
cont++;
if (cont == 3)
break;
temp = temp >> 1;
time++;
}
if (time == x - 2)
cout << min << " ";
//下一个数
min++;
}
}
int main()
{
int n;
while (cin >> n)
No110(n);
return 0;
}