题干传送门
先说结论:若用一个数组 c 来存数 i(i>1) 中 0 的个数,则:
- 当 i 为偶数, ci=c2i+1 ;
- 当 i 为奇数, ci=c⌊2i⌋ 。
举个例子,当 i=6 ,其二进制表示为 (110)2 。 2i 即为 3 ,二进制表示为 (11)2 ,相当于将 n 的二进制表示去掉最后一位 。而去掉的这一位刚好为 0 ,因此要在 c2i 的基础上加上 1 。奇数同理。
这样以后,就可以 O(n) 处理出 107 内的 c 。
最后,再前缀和预处理一下 c 就可以 O(1) 询问了。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include<bits/stdc++.h> using namespace std; const int maxn=10000001; int c[maxn]; int q[maxn]; int n,m,l,r; void init() { c[0]=1,c[1]=0; if(n==0) q[0]=0,q[1]=1; else if(n==1) q[0]=q[1]=1; else q[0]=q[1]=0; for(int i=2;i<maxn;i++) { if(i&1) c[i]=c[i>>1]; else c[i]=c[i>>1]+1; q[i]=q[i-1]; if(c[i]==n) ++q[i]; } } int main() { scanf("%d%d",&n,&m); init(); while(m--) { scanf("%d%d",&l,&r); if(l==0) printf("%d\n",q[r]); else printf("%d\n",q[r]-q[l-1]); } return 0; }
|