uva 10718 Bit Mask

原题:
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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值