//ugly method:8212K 188MS G++
// move bit: 380K 0MS G++
#include <cstdio>
#include <cstring>
#include <cmath>
int rankWeightArray[32];
// const int MAX = 2000005;
// int oneNumArray[MAX];
// int getOneNum(int num) {
// int res = 0;
// while(num) {
// if (num & 1) {
// res++;
// }
// num >>= 1;
// }
// return res;
// }
// void init() {
// for (int i = 0; i < MAX; i++) {
// oneNumArray[i] = getOneNum(i);
// // printf("%d\n", oneNumArray[i]);
// }
// }
int num;
// void solve(int num) {
// for (int i = num+1; i < MAX; i++) {
// if (oneNumArray[i] == oneNumArray[num]) {
// printf("%d\n", i);
// return;
// }
// }
// }
void init() {
int val = 1;
for (int i = 0; i < 32; i++) {
rankWeightArray[i] = val;
val <<= 1;
}
}
void solve(int num) {
int oneNumber = 0;
char adjacentOne = 0;
for (int i = 0; i < 31; i++) {
if (adjacentOne && ((num & rankWeightArray[i]) == 0)) {
// 01 -> 10
num |= rankWeightArray[i];
num ^= rankWeightArray[i-1];
for (int j = 0; j <= i-1; j++) {
num &= (~rankWeightArray[j]);
}
// printf("break %d %d\n", num, oneNumber-1);
break;
} else if (num & rankWeightArray[i]) {
adjacentOne = 1;
// printf("adjacentOne %d\n", i);
oneNumber++;
} else {
adjacentOne = 0;
}
}
for (int i = 0; i < oneNumber-1; i++) {
num ^= rankWeightArray[i];
}
printf("%d\n", num);
}
int main() {
init();
while(scanf("%d", &num) != EOF) {
if (!num) {
return 0;
}
solve(num);
}
}
最先想到的必然是暴力遍历所有比N大的数的1的数量,虽然可以AC,但绝对不是最优解法。
果然,更好的办法是:
从最低位开始找,找到第一个"01",然后将此"01"变为"10", 然后将此到最低位的所有"1"全部移到最低位:
例子:
1001110(73), 第一个 01是 红字部分,那么先把01变成10 -> 1010110,然后将后面所有的1移到最低位: 1010011,
原理一想就明白了。
discuss找到的神code,给跪:
#include <stdio.h>
int main()
{
int n,x;
while(scanf("%d",&n),n)
{
x=n&-n;
printf("%d\n",n+x+(n^n+x)/x/4);
}
}
后面找个位运算技巧看看.