百度之星初赛A第5题 BD String

题目链接:HDU5694

BD String

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 510    Accepted Submission(s): 225


Problem Description
众所周知,度度熊喜欢的字符只有两个:B和D。

今天,它发明了一种用B和D组成字符串的规则:

S(1)=B

S(2)=BBD

S(3)=BBDBBDD



S(n)=S(n1)+B+reverse(flip(S(n1))

其中, reverse(s) 指将字符串翻转,比如 reverse(BBD)=DBB flip(s) 指将字符串中的 B 替换为 D D 替换为 B ,比如 flip(BBD)=DDB

虽然度度熊平常只用它的电脑玩连连看,这丝毫不妨碍这台机器无与伦比的运算速度,目前它已经算出了 S(21000) 的内容,但度度熊毕竟只是只熊,一次读不完这么长的字符串。它现在想知道,这个字符串的第 L 位(从1开始)到第 R 位,含有的 B 的个数是多少?

 

Input
第一行一个整数 T ,表示 T(1T1000)  组数据。

每组数据包含两个数 L R(1LR1018)  。
 

Output
对于每组数据,输出 S(21000) 表示的字符串的第 L 位到第 R 位中 B 的个数。
 

Sample Input
  
  
3 1 3 1 7 4 8
 

Sample Output
  
  
2 4 3
 

题意:中文题

题目分析:我记得去年比赛貌似做过这道题,当时没有做出来,后来看评论区才知道是去年CCPC热身赛的题目。现在都还是这么弱,当时跟连新手村都没出差不多了。这题回头看一下发现还是挺水的,说是2的1000次方,实际最多也只能取2的60几次方。考虑每个新的增加的串都是由原来的串得来的,加上10的18次方数据量基本肯定是递归O(logn)算法无误了。

我们可以分别把1到L和1到R的B个数都求出来,然后相减。以R为例,把前面16个或者32个写出来数数基本规律也就出来了,前2^m有2^(m-1)个B,还要加上第2^m的B。这里注意要取恰好比R大的那个次方数,然后减去R到2^m的B的个数,不考虑BD互换的话这个串是原串前后翻转得到的,加上BD互换,因此只需求1到(2^m-R+1)D的个数,这里也就是为什么要取恰好比R大的原因了。这样依次递归的向前求解即可。时间复杂度O(logn)。注意数很大,要用unsigned long long(貌似)。

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
unsigned long long int two[1001],p[1001];
int T;
unsigned long long int l,r;

unsigned long long int slove(unsigned long long int x)
{
    if(x==0 ) return 0;
    if(x==1) return 1;
    if(x==2||x==3) return 2;
    unsigned long long int ans=0;
    for(int i=0;i<64;i++)
    {
        if(two[i]==x)
            return p[i]+1;
        if(two[i]<x&&two[i+1]>x)
        {
            ans+=p[i+1];
            ans-=(two[i+1]-x-1-slove(two[i+1]-x-1));
            return ans;
        }
    }
    return 0;
}

int main()
{
    two[0]=1;
    for(int i=1;i<64;i++)
    {
        two[i]=2*two[i-1];
        p[i]=two[i-1];
    }
    scanf("%d",&T);
    while(T--)
    {
        cin>>l>>r;
        l-=1;
        long long int ans=slove(r)-slove(l);
        cout<<ans<<endl;
    }
}


  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值