题目链接:点我
题意:
给你一个区间[a,b],让你从里面选一个连续子区间[x,y](子区间可以为[a,b]),把这个区间的所有数或起来x|x+1|x+2|…|y
你要使得区间[x,y]异或起来的结果要小于等于v。让你输出这个子区间的最大长度
题解:
我们可以先不考虑题目这个问题,换一个简单的问题:
对于任意一个数num,找到一个最大的x,x≤num,使其x|(x+1)|(x+2)|…|num>num
结论:
如果存在这样一个数x,那么num的二进制表示中的最低位的一个0,求这个0如果变成1会增加权值ans,然后x=num-ans
例如num二进制为:110101,那么x=110011
这个时候x|x+1|x+2|…|num刚好大于num,如果从x+1|x+2|…num就不会大于num(可以试试
那么可以说对于可选区间[x,y],如果把y=num,那么可选区间最长长度就是num-x
那么简化的问题就解决了,对于题目也就相当于可选区间[x,y]的右边界y不一定等于v,那么我们就可以枚举所有小于v的值,然后从中取最大区间就可以了
因为我们解决问题的时候求的x是num减去num的最低位二进制表示最低位0的权值,那么对于区间[x,y]右边界y的选取可以枚举0的位置就可以了
我们可以使用lowbit(~a)方式求num的最低位二进制表示最低位0的权值
因为~a就是把a按照二进制形式每一位取反,这样的话每一位的0变成了1,1变成了0
然后使用lowbit(b)方法求出来b的二进制下最低位1的权值
x&(-x),当x为0时结果为0;x为奇数时,结果为1;x为偶数时,结果为x中2的最大次方的因子。
而且这个有一个专门的称呼,叫做lowbit,即取2^k。
代码:
#include