1 条题解
-
0
首先,将给定物品的价值按降序排序,记为
接着,固定选择的物品数量为 进行分析。
此时,能够使选择的物品的平均价值达到最大值的集合为 。
进一步比较选择 个物品时的平均值和选择 个物品时的平均值的差异:\begin{equation} \frac{1}{K} \sum_{i=0}^{K-1} v_i - \frac{1}{K+1} \sum_{i=0}^K v_i = \frac{(K+1)}{K} \sum_{i=0}^{K-1} v_i - \sum_{i=0}^K v_i = \sum_{i=0}^{K-1} (v_i - v_K) \geq 0 \end{equation}
因此,可以得出结论:当选择 个物品时,平均价值的最大值一定大于或等于选择 个物品时的平均价值的最大值。
所以,选择 个物品时的最大平均价值,就是答案的第一行。
接下来,计算能够使物品平均价值达到最大值的选择方式的数量。
这时,根据上位 个物品的价值 ,可以分以下几种情况进行讨论:1. 当 时
在这种情况下,随着选择的物品数量增加,选择的物品的平均值会逐渐下降。
因此,只需计算出由 构成的集合的选择方式。
设 的个数为 ,
的个数为 ,
则答案为 $(YX)。2. 当 时
在这种情况下,即使增加选择的物品数量,选择的物品平均值仍然可能保持最大值。
这种情况发生在所有选择的物品的价值都等于 时。
此时,物品的选择数量可以在 到 的范围内变化,
因此,设 的个数为 ,
答案为:
组合数 可以利用帕斯卡三角形进行预计算,时间复杂度为 。
综上所述,算法的总时间复杂度为:
- 排序:
- 计算平均值:
- 帕斯卡三角形的预计算:
- 计数选择方式:
因此,总时间复杂度为 ,能够在时间限制内完成。
另外,还存在基于阶乘和逆元预计算的时间复杂度为 的解法(这里省略具体细节)。
C++ 示例代码(利用帕斯卡三角形进行组合数的预计算)
using ll = long long; using R = double; // 组合数表 ll C[51][51]; // C[n][k] -> nCk void comb_table(int N) { for (int i = 0; i <= N; ++i) { for (int j = 0; j <= i; ++j) { if (j == 0 || j == i) { C[i][j] = 1LL; } else { C[i][j] = (C[i-1][j-1] + C[i-1][j]); } } } } int main(void) { int N, A, B; cin >> N >> A >> B; const int NMAX = 50; ll v[NMAX]; for (int i = 0; i < N; ++i) { cin >> v[i]; } comb_table(N); sort(v, v + N); reverse(v, v + N); R max_average = 0.0; for (int i = 0; i < A; ++i) { max_average += v[i]; } max_average /= A; int a_th_val_num = 0, a_th_val_pos = 0; for (int i = 0; i < N; ++i) { if (v[i] == v[A - 1]) { a_th_val_num++; if (i < A) { a_th_val_pos++; } } } ll cnt = 0LL; if (a_th_val_pos == A) { for (a_th_val_pos = A; a_th_val_pos <= B; ++a_th_val_pos) { cnt += C[a_th_val_num][a_th_val_pos]; } } else { cnt += C[a_th_val_num][a_th_val_pos]; } cout.precision(20); cout << fixed << max_average << endl; cout << cnt << endl; return 0; }
信息
- ID
- 5487
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 2
- 上传者