【每日一题】补档 AGC015D A or...or B Problem | 构造 | 困难

题目内容

原题链接

给定一个区间 [ A , B ] [A,B] [A,B] ,从中选出两个数 x x x y y y x x x 可以等于 y y y ,问 x x x y y y 的结果可以得到多少个不同的数。

数据范围

  • 0 ≤ A ≤ B < 2 60 0\leq A\leq B<2^{60} 0AB<260

题解

如果 A = B A=B A=B,那么答案就是 1 1 1 。特判即可。

对于 [ A , B ] [A,B] [A,B] 中的数, A A A B B B 的二进制表示前缀中相同的部分或运算后的值必然是确定的,所以这部分可以不用考虑了。

举个例子: A = 13 = 110 0 2 , B = 15 = 111 1 2 A=13=1100_2,B=15=1111_2 A=13=11002,B=15=11112,两者二进制都是以 11 11 11 开头的,这部分就是确定的,故这部分可以不用考虑了。

可以将其重新设置为 A = 0 0 2 , B = 1 1 2 A=00_2,B=11_2 A=002,B=112

B > A B>A B>A ,故两者从高位到低位的第一个不同的二进制数位 k k k k k k 必然是最高位。

那么我们可以把可选择的数 x x x y y y 分为三部分,其中 x ≥ y x\geq y xy

  • 选择 x k = 0 , y k = 0 x_k=0,y_k=0 xk=0,yk=0,取值范围为: [ A , 2 k − 1 ] [A, 2^k-1] [A,2k1]
  • 选择 x k = 1 , y k = 0 x_k=1,y_k=0 xk=1,yk=0,取值范围为: [ 2 k + A , 2 k + 1 − 1 ] [2^k+A, 2^{k+1}-1] [2k+A,2k+11]
  • 选择 x k = 1 , y k = 1 x_k=1,y_k=1 xk=1,yk=1,取值范围为: [ 2 k , 2 k + 2 s + 1 − 1 ] [2^k, 2^k+2^{s+1}-1] [2k,2k+2s+11] ,其中 s s s 为从高位到低位第二个为 1 1 1 的二进制位,当不存在时, s = − 1 s=-1 s=1

对于 x k = 0 , y k = 0 x_k=0,y_k=0 xk=0,yk=0,由于取值最小值为 A A A ,取值最大值为 2 k − 1 2^k-1 2k1 ,故或运算的值必然在这个范围内。
具体构造出值 v ∈ [ A , 2 k − 1 ] v\in[A, 2^k-1] v[A,2k1],令 x = y = v x=y=v x=y=v 即可。

对于 x k = 1 , y k = 0 x_k=1,y_k=0 xk=1,yk=0,第 k k k 位或运算结果为 1 1 1 ,那么只需要考虑低 k − 1 k-1 k1 位。因为 y ≥ A y\geq A yA ,所以或运算的结果必然 ≥ A \geq A A ,但是低 k − 1 k-1 k1 位至多是全部为 1 1 1 ,即 2 k − 1 2^k-1 2k1
具体构造出值 v ∈ [ 2 k + A , 2 k + 1 − 1 ] v\in[2^k+A, 2^{k+1}-1] v[2k+A,2k+11],令 x = 2 k , y = v − 2 k x=2^k,y=v-2^k x=2k,y=v2k 即可。

对于 x k = 1 , y k = 1 x_k=1,y_k=1 xk=1,yk=1,如果 B = 2 k B=2^k B=2k ,那么只能选择一个数。
否则 B > 2 k B>2^k B>2k s s s 为从高位到低位第二个为 1 1 1 的二进制位。

对于 b i t ∈ ( s , k ) bit\in(s,k) bit(s,k) 的二进制位 b i t bit bit ,这些必然不可能为 1 1 1
那么 v k , v k − 1 , ⋯   , v s + 1 v_k,v_{k-1},\cdots,v_{s+1} vk,vk1,,vs+1 这些二进制位都已确定。那么可以构造出 [ 2 k , 2 k + 2 s + 1 − 1 ] [2^k, 2^k+2^{s+1}-1] [2k,2k+2s+11]
具体构造出值 v ∈ [ 2 k , 2 k + 2 s + 1 − 1 ] v\in[2^k, 2^{k}+2^{s+1}-1] v[2k,2k+2s+11]

  • v < 2 k + 2 s + 1 − 1 v<2^{k}+2^{s+1}-1 v<2k+2s+11 x = v , y = 2 k x=v,y=2^k x=v,y=2k
  • v = 2 k + 2 s + 1 − 1 v=2^{k}+2^{s+1}-1 v=2k+2s+11 x = 2 k + 2 s , y = 2 k + 2 s − 1 x=2^k+2^{s},y=2^k+2^{s}-1 x=2k+2s,y=2k+2s1

当然,这里的 x k = 1 , y k = 0 x_k=1,y_k=0 xk=1,yk=0 x k = 1 , y k = 1 x_k=1,y_k=1 xk=1,yk=1 的取值区间可能会有交集。

因为 2 k < 2 k + A 2^k<2^k+A 2k<2k+A ,所以必然是 2 k + 2 s + 1 − 1 ≥ 2 k + A 2^{k}+2^{s+1}-1\geq 2^k+A 2k+2s+112k+A ,即 2 s + 1 − 1 ≥ A 2^{s+1}-1\geq A 2s+11A ,即 2 s + 1 > A 2^{s+1}>A 2s+1>A ,此时 A A A 的二进制为 1 1 1 的最高位小于等于 B B B 的二进制为 1 1 1 的次高位。

时间复杂度: O ( log ⁡ max ⁡ ( A , B ) ) O(\log \max(A,B)) O(logmax(A,B)) ,至多 60 60 60

代码

#include 
using namespace std;

typedef long long ll;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    ll A, B;
    cin >> A >> B;
    if (A == B) {
        cout << "1\n";
        return 0;
    }

    vector<int> vecA(60), vecB(60);
    for (int i = 0; i < 60; ++i) {
        vecA[i] = A % 2;
        vecB[i] = B % 2;
        A /= 2;
        B /= 2;
    }

    while (!vecA.empty() && vecA.back() == vecB.back()) {
        vecA.pop_back();
        vecB.pop_back();
    }

    int n = int(vecA.size());

    reverse(vecA.begin(), vecA.end());
    reverse(vecB.begin(), vecB.end());

    int s = -1;
    for (int i = 1; i < vecB.size(); ++i) {
        if (vecB[i] == 1) {
            s = n - 1 - i;
            break;
        }
    }

    ll ans = 0;

    A = 0;
    for (int i = 0; i < vecA.size(); ++i) A = A * 2 + vecA[i];

    ll R = (1ll << (n - 1)) + (1ll << (s + 1)) - 1;
    ll L = A;

    if (R >= (1ll << (n - 1)) + A) {
        R = (1ll << n) - 1;
        ans = R - L + 1;
    } else {
        ans = R - L + 1;
        ans += (1ll << (n - 1)) - 1 - A + 1;
    }

    cout << ans << "\n";

    return 0;
}

你可能感兴趣的:(算法竞赛,算法,思维,构造)