本文内容遵从CC版权协议 转载请注明出自: http://blog.csdn.net/masterluo
给定两个正整数x, k,求第k个最小的正整数y,满足y满足x+y = x|y. x (1≤x≤2 000 000 000), k(1≤k≤2 000 000 000)
将x,y用二进制表示,len[x], len[y]分别表示需要多少位二进制位表示x, y. xi表示x的二进制的低i位(从0开始).
(1):如果len[y]>len[x], 且y的低len[x]位全为0,这样的y都是满足x+y = x|y的。如x=11,则len[x]=4.
0000 1011
xxxx 0000
-----------
xxxx 1011
(2):y≤x时有多少个这样的满足x+y = x|y 呢?
设x=xn-1xn-2……x0,存在y≤x满足x+y = x|y.如果xi( 0≤i<n)如果xi=0,则yi可以是0/1, 如果xi=1,则yi=0.故x=xn-1xn-2……x0时存在2^k(k为x二进制位中0的个数)个y(y≤x),使其满足x+y = x|y.
(3):y≤x时不存在除(2)外的其它y满足方程x+y = x|y.由二可知当y≤x时要满足方程x+y = x|y,即在x+y的任何一位都不能产生进位.用反证法证明.设最低一次进位是在第i位.由于第i位发生了进位且为第一次进位,则一定xi=1, yi=1. carryi-1=0(carryi表示第i位的进位值). 此时x+y结果为z, zi=(xi+yi)%2=0. x|y的结果为w. wi=(xi|yi)=1. zi != wi.故第i位不可能产生进位,得证。
由上面分析可以得到一个很简单的求解方法:第k小的y就是将x扩展(高位补0),从低位向高位填充k的二进制位。如果xi=0,填充一位k的二进制位。如果xi=1, 则yi=0.直至将所有的k的二进制全部填充即可。
-
#include <string>
-
#include <iostream>
-
using namespace std;
-
-
class BitwiseEquations {
-
public:
-
long long kthPlusOrSolution ( int, int );
-
string getBin ( int );
-
-
};
-
-
/*
-
*返回x的二进制形式的字符串
-
*/
-
-
string BitwiseEquations:: getBin ( int x ) {
-
string ret= "";
-
if (x== 0 ) {
-
ret= "0";
-
return ret;
-
}
-
while (x> 0 ) {
-
ret= char (x% 2+ '0' )+ret;
-
x/= 2;
-
}
-
return ret;
-
}
-
-
/*
-
*求第k小的y 满足x+y = x|y
-
*/
-
long long BitwiseEquations:: kthPlusOrSolution ( int x, int k ) {
-
string strx, strk;
-
strx=getBin (x );
-
strk=getBin (k );
-
int lx=strx. length ( ) -1;
-
int lk=strk. length ( ) -1;
-
-
string ret= "";
-
//填充k的二进制位
-
while (lx>= 0 && lk>= 0 ) {
-
if (strx [lx ]== '1' ) {
-
ret= "0"+ret;
-
--lx;
-
} else {
-
ret=strk [lk ]+ret;
-
--lx;
-
--lk;
-
}
-
}
-
//高位补0填充k的二进制位
-
while (lk>= 0 ) {
-
ret=strk [lk-- ]+ret;
-
}
-
-
long long rets= 0;
-
for ( int i= 0; i<ret. length ( ); ++i ) {
-
rets= (rets<< 1 )+ret [i ]- '0';
-
}
-
return rets;
-
}