[Brute force][规律] Jzoj P3084 超级变变变

Description

经过一系列的游戏之后,你终于迎来了今天的作业,第一个作业是预习一个超级美好的函数f(x),描述如下。


 


为了研究这个函数的性质,你决定定义一次变化为x=f(x)。


若x就经过若干次变化为k,则你就会觉得这是一个k变变数。


现在既然你已经这么觉得了,那就只好给定A,B,求有多少个A<=x<=B是k变变数了。


 

 

Input

输入包含三行。


第一行为一个整数k。


第二行为一个整数A。


第三行为一个整数B。


 

Output

   输出仅一行,表示答案。


 

 

Sample Input

Sample Input 1
13
12345
67890123


Sample Input2
1
234567
1234567

Sample Output

Sample Output1
8387584

Sample Output2
1000001
 

Hint

 对于50%的数据,0<=k,A,B<=10^6


对于100%的数据,0<=k,A,B<=10^18  A<=B

 

题解

  • 首先,我们可以把所有数转换成二进制来看
  • 那么两个操作,一个显然就是把二进制下最后一位的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 }

 

posted @ 2019-01-23 16:32  BEYang_Z  阅读(209)  评论(0编辑  收藏  举报