每日c/c++题 备战蓝桥杯(洛谷P4715 【深基16.例1】淘汰赛 题解)
洛谷P4715 【深基16.例1】淘汰赛 题解
题目大意
有 (2^n) 名选手进行淘汰赛,每场比赛两人对决,能力值高者胜出;若能力值相同,则编号较小者胜出。最终决出冠军,要求输出亚军的编号。
解题思路
关键观察:亚军是决赛中与冠军对决的选手。而冠军必定是全局能力值最大的选手,亚军则是另一半区中能力值最大的选手。
分治策略:
- 将选手分为左右两半区。
- 分别找出左右半区的最大值及其位置。
- 比较左右半区的最大值,较大的为冠军,另一半区的最大值即为亚军。
代码解释
#include <bits/stdc++.h>
using namespace std;int power[1025] = {}; // 存储选手能力值
int n;int main() {cin >> n;int h = pow(2, n); // 总人数for (int i = 1; i <= h; ++i) cin >> power[i]; // 输入能力值(编号从1开始)int le_max = 0, ri_max = 0;int le_idx = 1, ri_idx = h / 2 + 1;// 找左半区最大值for (int i = 1; i <= h / 2; ++i) {if (power[i] > le_max) {le_max = power[i];le_idx = i;}}// 找右半区最大值for (int i = h / 2 + 1; i <= h; ++i) {if (power[i] > ri_max) {ri_max = power[i];ri_idx = i;}}// 比较两半区最大值,输出亚军编号if (le_max > ri_max) cout << ri_idx;else cout << le_idx;return 0;
}
代码逻辑分析
- 输入处理:读取 (n) 和 (2^n) 个能力值,存入数组
power
(编号从1开始)。 - 分半区查找:
- 左半区(前 (2^{n-1}) 个)遍历找到最大值
le_max
及其位置le_idx
。 - 右半区(后 (2^{n-1}) 个)同理找到
ri_max
和ri_idx
。
- 左半区(前 (2^{n-1}) 个)遍历找到最大值
- 决赛对决:比较两半区最大值,较大的为冠军,另一半区的最大值位置即为亚军。
关键细节
- 编号处理:数组从1开始存储,避免与C++中
pow(2, n)
的索引混淆。 - 相等能力值:当能力值相同时,代码默认保留先遇到的选手(编号较小),符合题意。
复杂度分析
- 时间复杂度:(O(2^n)),需遍历数组两次。
- 空间复杂度:(O(2^n)),存储能力值数组。
示例说明
样例输入:
2
5 4 3 2
执行过程:
- 左半区
[5, 4]
最大值为5(位置1)。 - 右半区
[3, 2]
最大值为3(位置3)。 - 比较5和3,5胜出为冠军,亚军为右半区的3(位置3)。
输出:
3
注意事项
- 数组越界:确保输入人数为 (2^n),避免访问
power[h+1]
。 - 特殊情况:当 (n=0) 时需单独处理(题目保证 (n \geq 1))。
总结
本题通过分治思想,将问题简化为两半区的局部最大值比较,避免了完整模拟淘汰赛的高复杂度。代码简洁高效,关键在于理解亚军必为另一半区最大值的逻辑。