題目連結:https://codeforces.com/problemset/problem/1796/C
題目大意:
定義一個集合 \(S\) 是合法的,當且僅當集合中任意兩個整數 \(x\) 和 \(y\) 滿足 \(x\) 被 \(y\) 整除或 \(y\) 被 \(x\) 整除。
有 \(t\) \((1\le t\le 2\times 10^4)\) 次詢問,每次給你兩個整數 \(l,r\) \((1\le l\le r \le 10^6)\),每次詢問給出兩個回答,第一個是在集合 \([l,r]\) 中選出整陣列成的合法集合的最大大小,第二個是大小最大的合法集合的個數。
解題思路:
這個倍數關係肯定只有 \(2\) 倍或者 \(3\) 倍的關係。
因為 \(4\) 倍關係(即如果有一個數 \(x\) 是另一個數 \(y\) 的四倍),因為 \(4 = 2 \times 2\),則我們其實可以再加入一個 \(2y\)。
其次 \(3\) 倍關係最多隻有一個,因為如果有兩個數 \(3\) 倍關係(\(3 \times 3 = 9 \gt 8 = 2 \times 2 \times 3\)),我們就可以得到三個數他們之間是 \(2\) 倍關係。
首先,對於一次查詢的 \(l\) 和 \(r\),按照 \(l, 2l, 4l, 8l, \ldots\) 的規則取數肯定能夠得到最多的數字。
我們可以按照這個邏輯確定我們最多能取的數的個數,我們令這個數為 \(m+1\)。則此時最大的數恰好是最小的數的 \(2^m\),即恰好有 \(m\) 個 \(2\) 倍的關係。
然後我們可以分析兩種情況的集合數量。第一種是 \(m\) 個 \(2\) 倍關係,第二種是 \(m-1\) 個 \(2\) 倍關係 + \(1\) 個 \(3\) 倍關係。
\(m\) 個 \(2\) 倍關係
設此時最小的數為 \(x\),則選擇的 \(m+1\) 個數為:\(x, 2x, 4x, \ldots, 2^mx\)。
\(x\) 能取的最小的數值很明顯是 \(l\),能取的最大的數字是 \(\lfloor \frac{r}{2^m} \rfloor\)
所以這一部分一共有 \(\lfloor \frac{r}{2^m} \rfloor - l + 1\) 個不同的選擇方案。
\(m-1\) 個 \(2\) 倍關係 + \(1\) 個 \(3\) 倍關係
同樣,設此時最小的數為 \(x\),則只有 \(x \times 2^{m-1} \times 3 \le r\) 且 \(m \gt 0\)(因為要騰出一個 \(2\) 倍關係變為 \(3\) 倍關係)時才有選擇方案。
此時 \(x\) 能取的最小的數仍然是 \(l\),能取的最大的數是 \(\lfloor \frac{r}{2^{m-1} \times 3} \rfloor\)
所以,最小值 \(x\) 有 \(\lfloor \frac{r}{2^{m-1} \times 3} \rfloor - l + 1\) 種不同的選擇方案。
然後 \(3\) 倍關係放到 \(m\) 個倍數關係中,一共有 \(C_m^1 = m\) 種方案,最終的方案數還要乘上 \(m\)。
所以這一部分一共有 \(\lfloor \frac{r}{2^{m-1} \times 3} \rfloor - l + 1\) 種不同的選擇方案。
特殊情況
要注意一種特殊情況,就是 \(m = 0\) 的情況,即最多隻能選 \(m + 1 = 1\) 個數的情況,此時 \([l, r]\) 範圍內任何一個數都可以選,選擇方案數為 \(r - l + 1\)。
示例程式:
#include <bits/stdc++.h>
using namespace std;
int T, l, r;
void cal(int l, int r) {
int m = log2(r/l);
if (m == 0) { // 特判:只能選一個數的情況
cout << 1 << " " << r - l + 1 << endl;
return;
}
int ans = r / (1<<m) - l + 1; // 這一部分是m個2倍關係的方案數
if ((l << m-1) * 3 <= r)
ans += m * ((r >> m-1) / 3 - l + 1); // 這一部分加的是m-1個2倍關係+1個3倍關係的方案數
cout << m+1 << " " << ans << endl;
}
int main() {
cin >> T;
while (T--) {
cin >> l >> r;
cal(l, r);
}
return 0;
}