Educational Codeforces Round 144 (Rated for Div. 2) C. Maximum Set

我们要选出最长的子序列,使得每一个数都是前一个数的倍数。因此自然我们可以想到选择最小值然后每次乘\(2\)。所以有 \(l\times 2^k \le r\),即\(k = \left\lfloor \log_2 \frac{r}{l}\right\rfloor\)。所以最大的集合大小就是\(k + 1\)

然后考虑最大的集合中最小值可能不同,我假设符合条件的最小值是\(l_1\),则有\(l_1\times 2^k \le r\),所以\(l_1 = \left\lfloor \frac {r}{2^k}\right\rfloor\)

其实序列中每一个数也不一定都是前一个数的\(2\)倍。但也不可能是大于\(3\)倍,因为\(4\)倍可以拆成两个\(2\)倍,\(5\)倍可以拆成一个\(2\)倍,一个\(3\)倍。

再考虑,\(3\)倍至多只有\(1\)个。考虑存在两个\(3\)倍的情况\(\{x,3x,9x\}\),如果符合条件,则一定存在更优的情况\(\{x,2x,4x,8x\}\)

我们考虑只有一个\(3\)倍的情况,应该是\(l_2 \times 3 \times 2^{k-1} \le r\),也即\(l_2 =\left\lfloor \frac{r}{3\times 2^{k-1}} \right\rfloor\)。然后考虑有\(k\) 个数是前一个数的倍数,可以任选一个替换为\(3\)倍。

因此最终答案就是\((l_1 - l + 1) + (l_2 - l + 1) \times k\)

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;

//#define int i64

using vi = vector<int>;
using pii = pair<int, int>;

const i32 inf = INT_MAX / 2;

const int mod = 998244353;

void solve() {
    int l, r;
    cin >> l >> r;
    int k = log2((double)r / l);
    cout << k + 1 << " ";
    int l1 = r / (1 << k);
    int l2 = r / ((1 << (k - 1)) * 3);
    cout << (max(0, l1 - l + 1) % mod + max(0, l2 - l + 1) * k % mod) % mod << "\n";
    return;
}

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

    int T;
    cin >> T;
    while (T--)
        solve();
    return 0;
}

posted @ 2024-11-11 15:53  PHarr  阅读(4)  评论(0编辑  收藏  举报