我们要选出最长的子序列,使得每一个数都是前一个数的倍数。因此自然我们可以想到选择最小值然后每次乘\(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;
}
标签:lfloor,144,Rated,int,Educational,times,le,right,using
From: https://www.cnblogs.com/PHarr/p/18539818