原题:
In bit-wise expression, mask is a common term. You can get a certain bit-pattern using mask. For
example, if you want to make first 4 bits of a 32-bit number zero, you can use 0xFFFFFFF0 as mask and perform a bit-wise AND operation. Here you have to find such a bit-mask.Consider you are given a 32-bit unsigned integer N. You have to find a mask M such that L ≤M ≤ U and N OR M is maximum. For example, if N is 100 and L = 50, U = 60 then M will be 59 and N OR M will be 127 which is maximum. If several value of M satisfies the same criteria then you have to print the minimum value of M.
Input
Each input starts with 3 unsigned integers N, L, U where L ≤ U. Input is terminated by EOF.
Output
For each input, print in a line the minimum value of M, which makes N OR M maximum.
Look, a brute force solution may not end within the time limit.
Sample Input
100 50 60
100 50 50
100 0 100
1 0 100
15 1 15
Sample Output
59
50
27
100
1
大意:
给你三个数,N,U,L。其中现在让你找一个数A,让A OR N最大。A这个数必须大于等于L小于等于U。如果A有多个,找出最小的那个A。而且给你的数是32位无符号整形。
#include <bits/stdc++.h>
using namespace std;
//fstream in,out;
int N[33],L[33],U[33],Ans[33];
void ConverBin(unsigned int x , int a[])
{
int i=32;
while(x)
{
a[i] = x % 2;
x = x / 2;
i--;
}
}
unsigned int ConverInt(int a[])
{
unsigned int ans = 0;
for(int i = 0 ;i <= 32 ;i++)
{
if(a[i] == 1)
{
for(int j=i;j<=32;j++)
{
ans+=(int)pow(2,32-j)*a[j];
}
break;
}
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
unsigned int n,l,u,k;
unsigned int ans;
// in.open("data.txt");
// out.open("answer.txt");
while(cin>>n>>l>>u)
{
ans = 0;
memset(Ans,0,sizeof(Ans));
memset(N,0,sizeof(N));
memset(U,0,sizeof(U));
memset(L,0,sizeof(L));
if(l == u )
{
cout<<l<<endl;
continue;
}
ConverBin(n,N);
ConverBin(u,U);
ConverBin(l,L);
/* for(int i=0;i<=32;i++)
cout<<U[i];
cout<<endl;
for(int i=0;i<=32;i++)
cout<<N[i];
cout<<endl;
for(int i=0;i<=32;i++)
cout<<L[i];
cout<<endl;*/
for(k=0;k<=32;k++)//从后往前,下限和上限的2进制相同的部分
{
if(U[k]!=L[k])
break;
Ans[k]=U[k];
}
for(int i=k;i<=32;i++)//相同的部分添加进来以后,找第一个N[i]==1而且U[i]==1的部分
{//此时,后面的数如果N[i]==1那么就把当前Ans[i]变成0否则变成1,其余的部分和U[i]相同
if(U[i] == 1&&N[i] == 1)
{
for(int j=i;j<=32;j++)
if(N[j]==1)
Ans[j]=0;
else
Ans[j]=1;
break;
}
else
Ans[i]=U[i];
}
/* for(int i=0;i<=32;i++)
cout<<Ans[i];
cout<<endl;*/
for(int i=0;i<=32;i++)//满足得到的数要大于等于L
{
if(Ans[i]==1&&L[i]==0)//最高位比L大,那肯定比L大
break;
if(Ans[i]==0&&L[i]==1)如果最高位比L小
{
for(int j=i;j<=32;j++)
{
if(Ans[j]==1&&L[j]==0)//发现高位Ans是1,L是0 跳出
break;
if(Ans[j]==0&&L[j]==0)//都是0跳过
continue;
Ans[j]=1;//就把这个比L小的位数变成1
}
break;
}
}
ans=ConverInt(Ans);
cout<<ans<<endl;
}
// in.close();
// out.close();
return 0;
}
解答:
这题不错,很锻炼思维哈。为了好审查,没用位运算。
首先确定要用贪心的思想,先把给的三个数都变成二进制数。然后从左往右比较U和L的二进制位,U[i]和L[i]之前的值都是相等的,并赋值到Ans[i]当中,在第一次遇到U[i]不等于L[i]时停止赋值。这样做的目的是因为,如果U和L的高位都相同,而且想要得到的数必须在这个区间当中,那么要得到的数的高位也必须和U和L相同。比如如下数据(28169 7177 20120 转换成2进制看一看!)
然后比较N和U,如果发现第一位N和U都是1等情况,那么Ans对应N来看,如果N是1,那么Ans为0,否则为1。这样做的原因是因为,如果发现N和U都是1,因为U是上限,那么把当前位的U变成0,那当前位后面数可以都变成1。
经过上面操作得到的数要比L大,操作见代码部分。
最后要用unsigned int,否则wa