Atcoder D

题目链接:http://agc015.contest.atcoder.jp/tasks/agc015_d

题意:给出两个数b,a(a>=b)问{a,a+1,....,b}的集合内取任意数求或运算最多能够表示多少个数。

题解:数据很吧不用想着暴力,主要是位运算一般都会想到用二进制来写。具体的写法详见代码注释,不好表达。

#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
ll getnum(ll A , ll B) {
    int len1 , len2;//len1表示第一个大于A的2进制位数,len2表示第一个大于B的二进制位数
    if(A == B) return 1;
    for(len1 = 0 ; ((ll)1 << len1) <= A ; len1++);
    for(len2 = 0 ; ((ll)1 << len2) <= B ; len2++);
    if(len2 < len1) {
        ll t;
        for(t = len1 - 2 ; t >= 0 ; t--)
            if(((ll)1 << t) & A) break;//先找到A中从大到小第二个1的位置。
        if(t == -1) t = 0;
        else t = ((ll)1 << (t + 1)) - 1;
        if(B <= t + 1) return ((ll)1 << len1) - B;//显然能组成(1 << (len1 - 1)|t)~ B 的所有情况。然后最大能组合到(1 << len1 - 1)~(1 << (len1 - 1))|B)由于t+1比B大所以两个区间是相交的所以直接1 << len1 - B
        return (((ll)1 << (len1 - 1) | t) - B + 1) + (((ll)1 << len1) - 1 - (((ll)1 << (len1 - 1)) + B) + 1);//同理只不过集合不相交,所以要分两个集合算一下
        
    }
    return getnum(A ^ ((ll)1 << (len1 - 1)) , B ^ ((ll)1 << (len2 - 1)));
    //位数相同就去掉首位继续比较,去掉首位的方法就是求一下异或。
}
int main() {
    ll A , B;
    cin >> B >> A;
    cout << getnum(A , B) << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/TnT2333333/p/6937250.html