[规律]JZOJ 3084 超级变变变

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
 

Data Constraint

 
 

Hint

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


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

分析

第一眼看题:不会吧别又是数论

再看一眼:不就是右移吗?

然后我们发现k变变数在二进制下都是有k的前缀的

所以计数也非常简单

唯一要注意的就是偶数:偶数还可以由偶数+1转来,所以偶数的要计算两次(不是乘二!虽然乘二也能过)

 

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
ll k,a,b;

ll Calc(ll r) {
    ll mxn=0ll,ans=0ll,rr=r;
    if (r<k) return 0ll;
    while (rr>k) rr>>=1ll,mxn++;
    if (rr==k) ans+=r%(rr*(1ll<<mxn))+1ll;
    mxn--;
    for (int i=0;i<=mxn;i++) ans+=1ll<<i;
    return ans;
}

int main() {
    scanf("%lld%lld%lld",&k,&a,&b);
    if (k) printf("%lld\n",Calc(b)-Calc(a-1ll)+(!(k++%2ll)?Calc(b)-Calc(a-1ll):0));
    else printf("%lld\n",b-a+1ll);
}
View Code

 

posted @ 2019-01-24 20:34  Vagari  阅读(141)  评论(0编辑  收藏  举报