题意: 给定 n n n,问 ∑ i = 1 n ( i ⊕ ( i − 1 ) ) \sum_{i=1}^n(i\oplus(i-1)) ∑i=1n(i⊕(i−1))。
数据范围: 1 ≤ n ≤ 1 0 9 1\leq n\leq 10^9 1≤n≤109
题解:
考虑一个数 x x x和其减 1 1 1后的 x − 1 x-1 x−1
对于偶数: x = 100100 , x − 1 = 100011 , x ⊕ ( x − 1 ) = 000111 x=100100,x-1=100011, x\oplus(x-1)=000111 x=100100,x−1=100011,x⊕(x−1)=000111
对于奇数: x = 100011 , x − 1 = 100010 , x ⊕ ( x − 1 ) = 000001 x=100011,x-1=100010,x\oplus(x-1)=000001 x=100011,x−1=100010,x⊕(x−1)=000001
可以发现两者的都为: x x x的二进制最低位 1 1 1往低位都补满的值,但是这样仍然不够。
考虑二进制中的每一位对答案的贡献次数:
对于二进制第 i i i位,则该位被补到使得该位对答案产生贡献时,一定是所有 x x x最低位 1 1 1不比第 i i i位低的时候。那么可以考虑到二进制第 i i i位一次的贡献为 2 i 2^i 2i,故若 x x x是 2 i 2^i 2i的倍数,则 x x x会对答案产生一个 2 i 2^i 2i贡献。那么只需要考虑所有的 2 2 2的幂即可。
代码:
typedef long long ll;
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* @param n int整型
* @return long长整型
*/
long long Sum(int n) {
// write code here
ll now = 1, res = 0;
while(now <= n) {
res += n / now * now;
now <<= 1;
}
return res;
}
};