1.题目描述:点击打开链接
2.解题思路:本题要求找一个尽量小的数字,使得它大于D,且二进制表示中1的个数在区间[s1,s2]中。比赛时候想了好久,终于想到一个比较诡异的做法:如首先把D分解成二进制并把每一位都放到数组base中,并用num来统计当前1的个数。如果最低位是0,那么先把它变成1,并检查此时1的个数是否符合要求。接下来,开始不停地寻找形如”11..1110“的序列,并把这段全部取反,变成”00...0001“,更新num,并检查是否符合题意。如果不符合,那么把0由小到大逐个置位,并检查num是否符合题意。如果都不符合,那么继续重复上述过程,直到符合题意为止。不过需要注意转换成答案时候要变成long long型。
3.代码:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<sstream>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<complex>
#include<functional>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define me(s) memset(s,0,sizeof(s))
#define rep(i,n) for(int i=0;i<(n);i++)
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair <ll,ll> P;
int D, s1, s2;
const int N = 100 + 10;
int base[N];
int cnt;
void change(int x)
{
cnt = 0;
while (x>0)
{
base[cnt++] = x % 2;
x >>= 1;
}
}
void print()
{
for (int i = 0; i<cnt; i++)
printf("%d", base[i]);
puts("");
}
int bitcount(ll a)
{
if (!a)return 0;
return bitcount(a / 2) + (a & 1);
}
bool check(int x)
{
if (s1 <= x&&x <= s2)return false;
return true;
}
void test()
{
for (int i = 0; i < 33; i++)
base[i] = 1;
ll ans = 0;
for (int i = 0; i < 33; i++)
ans += ((ll)base[i] << i);
cout << ans << endl;
}
int main()
{
int T;
int rnd = 0;
//test();
scanf("%d", &T);
while (T--)
{
me(base);
scanf("%d%d%d", &D, &s1, &s2);
change(D);
//print();
int num = bitcount(D);
int up = max(s2, cnt);
int st = 0, ed = 0;
if (base[0] == 0)
{
base[0] = 1;
num++;
if (!check(num))goto x1;
}
do
{
for (int i= 0; i < up + 10;i++)
if (base[i]) { st = i; break; }//找形如“11...1110”的序列
for (int i = st; i < up + 10;i++)
if (!base[i]) { ed = i; break; }
for (int i = st; i <= ed; i++)
{
base[i] = !base[i];
}
num -= (ed - st - 1);
if (!check(num))break;
for (int i = st; i < ed; i++)
{
base[i] = !base[i];
num++;
if (!check(num))break;
}
} while (check(num));
x1:;
ll ans = 0;
for (int i = 0; i<up+10; i++)
ans += ((ll)base[i]<<i);
printf("Case #%d: %lld\n", ++rnd, ans);
}
}