观察一下,将整个过程写出来,会发现形成一棵满二叉树,每一层要么全是0,要么全是1。
输出的顺序是其中序遍历。
每一层的序号形成等差数列,就计算一下就可以出来每一层覆盖到的区间的左右端点。
复杂度O(log(n))。
#include<cstdio> using namespace std; typedef long long ll; ll n,l,r; bool a[66]; int e; int main() { // freopen("b.in","r",stdin); scanf("%I64d%I64d%I64d",&n,&l,&r); if(n==0) { puts("0"); return 0; } while(n) { a[++e]=n%2ll; n/=2ll; } ll j=1; int ans=0; for(int i=e;i;--i) { if(a[i]) { ll L=(l-j)/(j*2)+((l-j)%(j*2)!=0); if(l<j) L=0ll; ll R=(r-j)/(j*2); if(r<j) R=-1ll; ans+=(int)(R-L+1ll); } j*=2ll; } printf("%d\n",ans); return 0; }
【找规律】Divide by Zero 2017 and Codeforces Round #399 (Div. 1 + Div. 2, combined) B. Code For 1
原文:http://www.cnblogs.com/autsky-jadek/p/6423618.html