The Next

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2706    Accepted Submission(s): 961

Problem Description

Let L denote the number of 1s in integer D’s binary representation. Given two integers S1 and S2, we call D a WYH number if S1≤L≤S2.
With a given D, we would like to find the next WYH number Y, which is JUST larger than D. In other words, Y is the smallest WYH number among the numbers larger than D. Please write a program to solve this problem.

Input

The first line of input contains a number T indicating the number of test cases (T≤300000).
Each test case consists of three integers D, S1, and S2, as described above. It is guaranteed that 0≤D<231 and D is a WYH number.

Output

For each test case, output a single line consisting of “Case #X: Y”. X is the test case number starting from 1. Y is the next WYH number.

Sample Input

3 
11 2 4 
22 3 3 
15 2 5

Sample Output

Case #1: 12 
Case #2: 25
Case #3: 17

考虑比D大1的数D+1,先算出D+1中1的个数L,然后分情况讨论:

如果L大于S2 
    因为我们现在要减少1的个数,而且我们现在只能加,所以考虑二进制中的最后一个1,只有让这一位向前进位,我们才能减少1的个数,所以对于这种情况,我们先找出最后一个1所在的位置,然后把该位的1向前进位。

如果L小于S1 
    这个好说,我们从二进制的最右边向左边扫,把遇到的0全部变成1,知道满足条件为止。

#include<iostream>
using namespace std;
#define ll long long
using namespace std;
int is_1s(ll a)
{
	int ans = 0;
	for (int i = 0; i < 32; i++)
		if ((1 << i)&a)
			ans++;
	return ans;
}
int main()
{
	int t;
	ll d;
	int s1, s2;
	cin >> t;
	int Case = 1;
	while (t--)
	{
		scanf("%lld%d%d", &d, &s1, &s2);
		//cin >> d >> s1 >> s2;
		d++;
		int len = is_1s(d);
		if (len >= s1&&len <= s2)
		{
			printf("Case #%d: %lld\n", Case++, d);
			//cout << "Case #" << Case++ << ": " << d << endl;
			continue;
		}
		while (1)
		{
			if (len < s1)
			{
				for(int i=0;i<32;i++)
					if (((1 << i)&d) == 0)
					{
						d = d | (1 << i);
						len++;
						if(len==s1)
						break;
					}
				printf("Case #%d: %lld\n", Case++, d);
					//cout << "Case #" << Case++ << ": " << d << endl;
					break;
			
			}
			if (len > s2)
			{
				for(int i=0;i<32;i++)
					if ((1 << i)&d)
					{
						d += (1 << i);
						break;
					}
				len = is_1s(d);
				if (len>=s1&&len<=s2)
				{
					printf("Case #%d: %lld\n", Case++, d);
					//cout << "Case #" << Case++ << ": " << d << endl;
					break;
				}
			}
		}
	}
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值