Hdu_5694 BD String(递推)

题意:

按照题目中的规则构造字符串。

思路:

最开始第一眼被题目的数据吓到了,2^1000,根本不知道从哪儿入手。看了题解之后发现没有那么夸张,因为L,R都是在LL的范围内的,所以找到规律的话LL一定是足够的。因为是按照题目的规则构造字符串,所以要把性质给挖掘出来才有做的可能。

1. 第n个串的长度Len[n]为2^n-1

2. 第2^n位上的字符一定是B;

3. 第n个串包含3个部分:前面2^(n-1),B,后面2^(n-1);其中前面部分包含的B的个数等于后半部分包含的D的个数,可以推出第n个串包含2^(n-1)+1个B;

4. 同理,任意取i,2^n+i与2^n-i关于2^n对称,一个D对应一个B。

以上:

问题要求我们求出L到R的B的个数,可以转化为求出0-R中B的个数减去0-L-1中B的个数,因为依据性质从0开始去计算更方便。

对于任意从0开始的长度为a的串,包含三个部分:前2^x-1,B,后a-2^x;

从大到小枚举x,则对于每一个串都有(a-2^x)<(2^x-1),则我们可以确定得到(a-2^x+1)个B,依据性质3,4。

同时更新a的长度为2^(x+1)-1-a

很巧妙的替换,一道好题。

代码实现:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define LL long long

using namespace std;

LL T;
LL L,R;
LL calculate(LL a);
int main()
{
    scanf("%I64d",&T);
    while( T-- ){
        scanf("%I64d %I64d",&L,&R);
        printf("%I64d\n",calculate(R)-calculate(L-1));
    }
    return 0;
}

LL calculate(LL a){
    LL res = 0;
    for( int i = 62; i >= 0; i-- ){
        //注意这个1默认类型的越界
        LL len = (LL)1<<i;
        if( a >= len ){
            res += a-len+1;
            a = (len<<1)-1-a;
        }
    }
    return res;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值