hdu5491(2015合肥网络赛H题)

来源:互联网 发布:js中target属性 编辑:程序博客网 时间:2024/04/29 12:03

题意:

给出三个数字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
原创粉丝点击