题意:给出一个数字n,把n拆成 n/2 n%2 n/2三个整数,重复拆分直到所有的数字<=1,求指定区间l,r中有多少个1
思路:对于一个特定的数字n,经过拆分之后,一定有n个1,其余是0.而总长度可以由n能够多少次二分得到。即len
得到总长度以后,对整个区间进行二分搜索,对于二分的区间L,R满足完全在l,r之内时,当前数字拆分的所有1一定累加到区间内,即当前数字如果是num则返回num
对于任何一个二分区间L,R,一定满足L+R是偶数,所以mid得到的是num%2的结果,所以每次二分对两侧区间和中间值进行下一次搜索。整体搜索类似于线段树。
代码:
#include<iostream>
#include<algorithm>
using namespace std;
long long n;
long long l, r;
long long query(long long L, long long R, long long num)
{
if(r<L || l > R || num == 0)
return 0;
if(l <= L && R <= r)
return num;
long long mid = (L + R) >> 1;
long long a, b, c;
a = query(L, mid-1, num/2);
b = query(mid+1, R, num/2);
c = query(mid, mid, num%2);
return a+b+c;
}
int main()
{
while(cin >> n)
{
cin >> l >> r;
long long len = 1, r = 2;
long long p = n;
while(p>1)
{
len += r;
p >>= 1;
r <<= 1;
}
long long res = query(1, len, n);
cout << res;
}
return 0;
}