AtCoder Beginner Contest 188 C 题,https://atcoder.jp/contests/abc188/tasks/abc188_c。
2 N 2^N 2N players, labeled 1 1 1 through 2 N 2^N 2N, will compete against each other in a single-elimination programming tournament.
The rating of Player i i i is A i A_i Ai. Any two players have different ratings, and a match between two players always results in the victory of the player with the higher rating.
The tournament looks like a perfect binary tree. Formally, the tournament will proceed as follows:
Find the label of the player who will take second place, that is, lose in the final match.
Input is given from Standard Input in the following format:
N N N
A 1 A 2 ⋯ A 2 N A_1 A_2 \cdots A_{2^N} A1A2⋯A2N
Print the label of the player who will take second place.
2
1 4 2 5
2
First, there will be two matches between Players 1 1 1 and 2 2 2 and between Players 3 3 3 and 4 4 4. According to the ratings, Players 2 2 2 and 4 4 4 will win.
Then, there will be a match between Players 2 2 2 and 4 4 4, and the tournament will end with Player 4 4 4 becoming champion.
The player who will lose in the final match is Player 2 2 2, so we should print 2 2 2.
2
3 1 5 4
1
First, there will be two matches between Players 1 1 1 and 2 2 2 and between Players 3 3 3 and 4 4 4. According to the ratings, Players 1 1 1 and 3 3 3 will win.
Then, there will be a match between Players 1 1 1 and 3 3 3, and the tournament will end with Player 3 3 3 becoming champion.
The player who will lose in the final match is Player 1 1 1, so we should print 1 1 1.
4
6 13 12 5 3 7 10 11 16 9 8 15 2 1 14 4
2
2 N 2^N 2N 个玩家,编号从 1 1 1 到 2 N 2^N 2N。这些玩家正在进行一对一编程淘汰赛。第 i i i 个玩家的胜率用 A i A_i Ai 表示,任意两个不同的玩家的胜率是不一样的。两个玩家进行淘汰的时候,淘汰胜率较小的哪个玩家。问最终获得第二名的玩家编号是多少。
我们使用样例数据 3 3 3 来分析一下,整个淘汰的过程。
从上面的数据分析可以看到。本题的考点就是一个二叉搜索树,因此最简单的方法就是使用递归来实现。这里我用数组来实现,这样能更好的理解整个数据变化过程。
有几个二叉树的基本性质需要了解。
1、当前节点编号为 i i i,其父节点编号为 i 2 \frac{i}{2} 2i。
2、当前节点编号为 i i i,其右兄弟节点编号为 i + 1 i+1 i+1。
这样,我们通过控制数组下标,来实现样例数据分析的过程。
我们使用结构体。结构体定义如下。
typedef struct _DATA {
int value;
int idx;
} DATA;
注意,本题定义的数组大小为 2 N 2^N 2N。因此 N N N 的最大值为 16 16 16,数组最大为 65536 65536 65536。
数据的最大值为 1 0 9 10^9 109,因此用 int 可以。
//https://atcoder.jp/contests/abc188/tasks/abc188_a
//A - Three-Point Shot
#include
using namespace std;
//如果提交到OJ,不要定义 __LOCAL
//#define __LOCAL
const int MAXN = 65538;
typedef struct _DATA {
int value;
int idx;
} DATA;
DATA a[MAXN];
int main() {
#ifndef __LOCAL
//这部分代码需要提交到OJ,本地调试不使用
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#endif
int n;
cin>>n;
n=pow(2, n);
for (int i=1; i<=n; i++) {
cin>>a[i].value;
a[i].idx = i;
}
while (n>2) {
for (int i=1; i<=n; i+=2) {
if (a[i].value<a[i+1].value) {
a[i/2+1].value = a[i+1].value;
a[i/2+1].idx = a[i+1].idx;
} else {
a[i/2+1].value = a[i].value;
a[i/2+1].idx = a[i].idx;
}
}
n/=2;
}
if (a[1].value>a[2].value) {
cout<<a[2].idx<<"\n";
} else {
cout<<a[1].idx<<"\n";
}
#ifdef __LOCAL
//这部分代码不需要提交到OJ,本地调试使用
system("pause");
#endif
return 0;
}
O ( l o g 2 N ) O(log{2^N}) O(log2N)。
O(N)。
使用完全二叉树的基本定义,我们可以实现递归。
//https://atcoder.jp/contests/abc188/tasks/abc188_a
//A - Three-Point Shot
#include
using namespace std;
//如果提交到OJ,不要定义 __LOCAL
//#define __LOCAL
const int MAXN = 65538;
int a[MAXN];
int n;
int solve(int l, int r) {
//出口
if (l+1==r) {
return a[l]>a[r]?l:r;
}
//递归
int mid = (l+r)/2;
int x=solve(l, mid);
int y=solve(mid+1, r);
if (l==1 && r==n) {
cout<<(a[x]>a[y]?y:x)<<"\n";
return 0;
} else {
return a[x]>a[y]?x:y;
}
}
int main() {
#ifndef __LOCAL
//这部分代码需要提交到OJ,本地调试不使用
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#endif
cin>>n;
//n=1<
n=pow(2, n);
for (int i=1; i<=n; i++) {
cin>>a[i];
}
if (2==n) {
cout<<(a[1]>a[2]?'2':'1')<<'\n';
return 0;
}
solve(1, n);
#ifdef __LOCAL
//这部分代码不需要提交到OJ,本地调试使用
system("pause");
#endif
return 0;
}
没有我想象中好。递归只是代码简洁。
O ( l o g 2 N ) O(log{2^N}) O(log2N)。
O(N)。