EOJ 3303 1的個數最多的整數(位運算)

題目

http://acm.ecnu.edu.cn/problem/3303/

題意:給定整數 a 和 b,輸出區間 [a,b] 中對應二進制表示含 1 的個數最多的整數。如果存在多個解,則輸出符合條件的最小的整數。

解題思路

由於數據量較大,因此窮舉只能過50%的小數據,ab數值一大就超時。

直觀地看,要讓區間[a, b]內1的個數最多,那就要在左界a的基礎上,在它的二進制串上儘可能增加1,同時不超過b。因爲要求輸出最小的整數,所以要對a的二進制串從低到高,嘗試讓處於低位的0變成1,直到超出b。

有兩種辦法:

  1. 如果某數字num低位有0, 可以通過讓num和num+1做或運算,將最低位變成1。這種方法不需要將ans顯式地轉爲二進制。注意相關變量保險起見要聲明爲unsigned long long,原因是a,b可以取到2631 ,在a基礎上運算可能導致數值越界。
  2. 思想同上,只是用bitset類來存放二進制數,用weight數組存每個二進制位對應的十進制數,從低到高掃描bitset,出現0時,不使用位運算而是對a直接累加上十進制數。注意變量也要聲明爲unsigned long long,因爲weight[64] = 264>(2631) .

AC代碼

#include <bits/stdc++.h>

using namespace std;
typedef unsigned long long uLL;

uLL adding_solve(uLL a, uLL b)
{
    uLL ans = a;
    while ( (ans|(ans+1)) <= b ) //從低到高,嘗試讓低位0變成1
        ans |= (ans+1);
    return ans;
}

uLL bitset_solve(uLL a, uLL b)
{
    uLL weight[64]; //每個二進制位對應的十進制數,必須是unsigned LL, 因爲2^64 > 2^63-1
    weight[0] = 1;
    for (int i = 1; i < 64; ++i)
        weight[i] = weight[i-1] * 2;
    uLL a, b, ans;
    cin >> a >> b;
    bitset<64> bits(a); //用a初始化bitset
    ans = a;
    for (int i = 0; i < 64; ++i)
    {
        if (bits[i] == 0)
        {
            ans += weight[i]; //用十進制加法,嘗試讓低位0變成1
            if (ans > b) //回溯,終止
            {
                ans -= weight[i];
                break;
            }
        }
    }
    return ans;
}

int main()
{
    ios::sync_with_stdio(false);
    int kase;
    cin >> kase;
    for (int t = 1; t <= kase; ++t)
    {
        uLL a, b;
        cin >> a >> b;
        uLL ans = bitset_solve(a, b);
        cout << "Case " << t << ": " << ans << endl;
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章