hdu5491(2015合肥网络赛H题)

题意:

给出三个数字D、s1和s2,用L来表示D的二进制表示中1的个数,L在区间[s1,s2]中,我们要找到离D最近的并且大于D的一个数字,且这个数字的L也落在区间[s1,s2]中。


思路:

一直超时。。。不知道为啥,后来也不知道为啥就不超时了。。。说说不超时的代码。

对于一个数字D,我们先给它进行+1操作,看D+1是否满足L值落在区间[s1,s2]中,如果满足就输出,不满足就进行如下操作:

我们从最低位开始找,找到第一段连续的1,把这些1都变成0,然后把这些1的前面那个位置变成0,就如10111100110变成10111101000,然后我们要把最新得到的这个数的1的个数变成s1,从最低位开始补1就好了。


代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

long long G(long long n)
{
    long long tmp = n - ((n >>1) &033333333333) - ((n >>2) &011111111111);
    return ((tmp + (tmp >>3)) &030707070707) %63;
}

int main() {
    long long t;
    long long d, s1, s2;
    scanf("%I64d",&t);
    for(long long kase = 1; kase <= t; kase++) {
        scanf("%I64d%I64d%I64d",&d,&s1,&s2);
        long long x = d + 1;
        long long num = G(x);
        if(num >= s1 && num <= s2) {
            printf("Case #%I64d: %I64d\n",kase,x);
            continue;
        }
        bool flag = false;
        for(long long i = 1; ; i <<= 1) {
            if(flag == false) {
                if((d & i)) {
                    d -= i;
                    flag = true;
                }
            } else {
                if((d & i)) {
                    d -= i;
                    flag = true;
                } else {
                    d |= i;
                    break;
                }
            }
        }
        x = d;
        num = G(x);
        if(num >= s1 && num <= s2);
        else 
            x |= ((1 << (s1 - num)) - 1);
        printf("Case #%I64d: %I64d\n",kase,x);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值