题目:http://codeforces.com/contest/768/problem/B
题意:
给一个数n,和一个区间[l,r] (r-l<1e5,n<2^50),每次可以把数n分成(n/2,n%2,n/2)知道所有数变成0或1,问区间内有多少个1?
分析:
因为[l,r]的范围小于1e5,所以想到枚举区间中的第pos个数,判断这个数是0还是1即可。递归去判断最多50,所以不会超时。递归如何判断呢?每次把n去递归模拟,一层层往下,就可以找到第pos个位置,然后看一下是0还是1即可。
上面递归判断的思想稍微转化一下,线段树的结构呼之欲出(这不就是线段树吗WOW),所以找到n展开后的最大区间长度,然后在这个区间里去找[l,r],这就很容易了。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int query(LL n,LL L,LL R,LL l,LL r)
{
if(R<l||L>r||n==0)
return 0;
if(n==1)
return 1;
LL mid=l+r>>1;
return query(n/2,L,R,l,mid-1)+query(n%2,L,R,mid,mid)+query(n/2,L,R,mid+1,r);
}
int main()
{
LL n,l,r;
cin>>n>>l>>r;
LL len=1,x=n;
while(x>1){
len=len*2+1;
x>>=1;
}
printf("%d\n",query(n,l,r,1,len));
return 0;
}