您的位置:首页 > 理论基础 > 计算机网络

HDU 5491 The Next (2015年合肥赛区网络赛H题)

2015-09-28 10:39 399 查看
1.题目描述:点击打开链接

2.解题思路:本题要求找一个尽量小的数字,使得它大于D,且二进制表示中1的个数在区间[s1,s2]中。比赛时候想了好久,终于想到一个比较诡异的做法:如首先把D分解成二进制并把每一位都放到数组base中,并用num来统计当前1的个数。如果最低位是0,那么先把它变成1,并检查此时1的个数是否符合要求。接下来,开始不停地寻找形如”11..1110“的序列,并把这段全部取反,变成”00...0001“,更新num,并检查是否符合题意。如果不符合,那么把0由小到大逐个置位,并检查num是否符合题意。如果都不符合,那么继续重复上述过程,直到符合题意为止。不过需要注意转换成答案时候要变成long
long型。

3.代码:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<sstream>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<complex>
#include<functional>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

#define me(s)  memset(s,0,sizeof(s))
#define rep(i,n) for(int i=0;i<(n);i++)
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair <ll,ll> P;

int D, s1, s2;
const int N = 100 + 10;
int base
;
int cnt;

void change(int x)
{
    cnt = 0;
    while (x>0)
    {
        base[cnt++] = x % 2;
        x >>= 1;
    }
}

void print()
{
    for (int i = 0; i<cnt; i++)
        printf("%d", base[i]);
    puts("");
}

int bitcount(ll a)
{
    if (!a)return 0;
    return bitcount(a / 2) + (a & 1);
}
bool check(int x)
{
    if (s1 <= x&&x <= s2)return false;
    return true;
}

void test()
{
    for (int i = 0; i < 33; i++)
        base[i] = 1;
    ll ans = 0;
    for (int i = 0; i < 33; i++)
        ans += ((ll)base[i] << i);
    cout << ans << endl;
}
int main()
{
    int T;
    int rnd = 0;
    //test();
    scanf("%d", &T);
    while (T--)
    {
        me(base);
        scanf("%d%d%d", &D, &s1, &s2);
        change(D);
        //print();
        int num = bitcount(D);
        int up = max(s2, cnt);
        int st = 0, ed = 0;
        if (base[0] == 0)
        {
            base[0] = 1;
            num++;
            if (!check(num))goto x1;
        }
        do
        {
            for (int i= 0; i < up + 10;i++)
                if (base[i]) { st = i; break; }//找形如“11...1110”的序列
            for (int i = st; i < up + 10;i++)
                if (!base[i]) { ed = i; break; }
            for (int i = st; i <= ed; i++)
            {
                base[i] = !base[i];
            }
            num -= (ed - st - 1);
            if (!check(num))break;
            for (int i = st; i < ed; i++)
            {
                base[i] = !base[i];
                num++;
                if (!check(num))break;
            }
        } while (check(num));
    x1:;
        ll ans = 0;
        for (int i = 0; i<up+10; i++)
            ans += ((ll)base[i]<<i);
        printf("Case #%d: %lld\n", ++rnd, ans);
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: