题解
- 首先,我们可以把所有数转换成二进制来看
- 那么两个操作,一个显然就是把二进制下最后一位的1变成0,一个就是将二进制右移一位
- 这样每次修改的只可能是最后一个数,这样的话我们就可以想到,对于一个数若可以变成k
- 那么它在二进制下k一定是它的一个从1开始的子串(前继)
- 想到这里的话,其实就很容易做了
-
- 这题貌似还有一种极其暴力的算法,而跑的贼快
- 对于一个偶数,那么它可以拓展的就是2*n,2*n+1然后这两个数又可以往下拓展
- 暴力碾表算!!!
代码
1 #include <cstdio>
2 #include <cstring>
3 #define ll long long
4 using namespace std;
5 ll k,A,B,mi[640];
6 int tot[640],num[640];
7 ll calc(ll x)
8 {
9 if (x<k) return 0;
10 if (x==k) return 1;
11 memset(tot,0,sizeof(tot));
12 ll l=x,ans=0,p,q;
13 while (l>0) tot[++tot[0]]=l%2,l/=2;
14 for (int i=num[0];i<tot[0];i++) ans+=mi[i-num[0]];
15 for (int i=1;i<=tot[0];i++)
16 {
17 if (i>num[0]) p=0; else p=num[num[0]-i+1];
18 q=tot[tot[0]-i+1]; if (p>q) break;
19 if (i<=num[0]&&q>p) { ans+=mi[tot[0]-num[0]]; break; }
20 if (i>=num[0]&&q>p) ans+=mi[tot[0]-i];
21 if (i==tot[0]&&q>=p) ans++;
22 }
23 return ans;
24 }
25 int main()
26 {
27 scanf("%lld%lld%lld",&k,&A,&B),mi[0]=1;
28 for (int i=1;i<=63;i++) mi[i]=mi[i-1]*2;
29 if (k==0) { printf("%lld",B-A+1); return 0; }
30 if (B<k) { printf("0"); return 0; }
31 if (k%2==0) k/=2; ll l=k;
32 while (l>0) num[++num[0]]=l%2,l/=2;
33 printf("%lld",calc(B)-calc(A-1));
34 }