题意描述
给你一个区间,求一个集合 S , S ∈ [ l , r ] S,S\in[l,r] S,S∈[l,r] 的最大长度与最长集合的个数。
需要满足 ∀ i , j ∈ S , i ∣ j 或 j ∣ i \forall i,j \in S , \ \ i | j \ 或 \ j | i ∀i,j∈S, i∣j 或 j∣i,集合长度为 1 1 1 默认合法。
简要分析
不难发现,最长长度的集合长这样 l , l × 2 , l × 2 2 , . . . , l × 2 x l ,l\times 2,l\times 2^2 , ...,l \times2^x l,l×2,l×22,...,l×2x。
那么我们就可以处理出集合的最长长度。
接下来考虑仅 × 2 \times 2 ×2 时的集合数量。
显然,我们只需将 r r r 除以 x − 1 x - 1 x−1 次 2 2 2 就可以知道集合的初值所属于的最大区间,即求出了集合数量。
我们考虑到,可以将集合中的某一个 × 2 \times 2 ×2 替换成 × 3 \times3 ×3。
如果替换两个即等价于 × 9 \times 9 ×9,这时不妨使用 3 3 3 个 × 2 \times 2 ×2 即为 × 8 \times 8 ×8 得到更优答案。
对于计算存在一个 × 3 \times 3 ×3 的集合个数,我们如法炮制。
将 r r r 除以 x − 1 x-1 x−1 次 2 2 2 随后再除以 3 3 3 就可以知道集合的初值所属于的最大区间,即求出了集合数量。
时间复杂度 O ( T log r ) O(T\log r) O(Tlogr)。
代码实现
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
using namespace std;
typedef long long ll;
const ll maxn = 1e5 + 7;
const ll INF = 1e9 + 7, MOD = 998244353;
inline ll read() {
char cCc;
ll xXx = 0, wWw = 1;
while (cCc < '0' || cCc > '9')
(cCc == '-') && (wWw = -wWw), cCc = getchar();
while (cCc >= '0' && cCc <= '9')
xXx = (xXx << 1) + (xXx << 3) + (cCc ^ '0'), cCc = getchar();
xXx *= wWw;
return xXx;
}
inline void write(ll xXx) {
if (xXx < 0)
putchar('-'), xXx = -xXx;
if (xXx > 9)
write(xXx / 10);
putchar(xXx % 10 + '0');
}
void solve() {
ll n = read(), m = read();
ll tmp = m, ans = 0, cnt = 0, lim;
if (n * 2 > m) {
cout << 1 << " " << m - n + 1 << '\n';
return;
}
while (tmp >= n) cnt++, tmp /= 2;
lim = cnt - 1;
tmp = m;
while (lim--) tmp /= 2;
ans = tmp - n + 1;
lim = cnt - 2;
tmp = m;
while (lim--) tmp /= 2;
ans += max(0ll, (tmp / 3 - n + 1) * (cnt - 1));
cout << cnt << ' ' << ans << endl;
}
signed main() {
// freopen("code.in","r",stdin);
// freopen("code.out","w",stdout);
ll T = read();
while (T--)solve();
return 0;
}