CF1796C C. Maximum Set 题解 排列组合
题目链接: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;
}