• [HDU5969]最大的位或


    题目

    B君和G君聊天的时候想到了如下的问题。
    给定自然数(l)(r) ,选取(2)个整数(x,y)满足(l leq x leq y leq r),使得(x|y)最大。
    其中(|)表示按位或,即(C,C++,Java)中的(|)运算。
    Input
    包含至多(10001)组测试数据。
    第一行有一个正整数,表示数据的组数。
    接下来每一行表示一组数据,包含两个整数(l,r)
    保证(0 leq l leq r leq 1018)
    Output
    对于每组数据输出一行,表示最大的位或。
    Sample Input
    5
    1 10
    0 1
    1023 1024
    233 322
    1000000000000000000 1000000000000000000
    Sample Output
    15
    1
    2047
    511
    1000000000000000000

    解说

    题意极其容易理解。
    日常习惯先写个暴力试试,意料之中的(T)了。没办法,毕竟每次询问都是(O(n^2))
    接下来我思路断了,于是瞎试,把(l)(r)每个数挨个位或一遍,结果所有样例都对上了。于是我开始思考这会不会就是正解?好像确实是呢,位或是只要两个数同一位有一个是(1)那么结果就是(1),那么我全位或一遍就相当于找了这两个数之间都有哪些位出现了(1)。虽然题目问的是找两个数,但稍微想一下就可以发现在这两个数之间是肯定可以找到把出现(1)的位都涵盖的两个数的。现在的单次时间效率是(O(n))
    (O(n))的时间效率还能过不了?天理难容!交……(T)了。
    看来要么是还有常数级效率的方法要么就是(O(logn))的方法。常数级不太可能,那么就只能试着把刚才的思想改成(O(logn))的方法,那肯定用到位运算。
    和刚才做法等价的做法就是在(r)的范围内枚举每一位的(1),这样就相当于刚才的找(1)操作了。
    终于(A)了。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;//记得开long long
    ll read(){
       ll s=0,w=1;
       char ch=getchar();
       while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
       while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
       return s*w;
    } 
    int main(){
        int t;
        scanf("%d",&t);
        while(t--){
            ll l,r,tool=1,move=0;//tool就是枚举用的,move表示现在在第几位
            l=read(); r=read();
            while((l|(tool<<move))<=r){
            	l|=(tool<<move);
            	move++;//左移
    		}
            printf("%lld
    ",l|r);
        }
        return 0;
    }
    

    幸甚至哉,歌以咏志。

  • 相关阅读:
    什么是 DLL?
    如何用vc创建和读取xml文件??
    VC中调用 Excel 的总结
    Excel.cpp和Excel.h
    SQL中也可以用格式字符串定制日期转字符串
    REVERT权限切换
    透明数据加密
    批量恢复数据库
    FILESTREAM
    eclipse Tomcat热启动maven install Jrebel
  • 原文地址:https://www.cnblogs.com/DarthVictor/p/12833327.html
Copyright © 2020-2023  润新知