2018牛客网暑期ACM多校训练营(第六场)A(模拟)
题目描述:
有一个比赛有n轮,一共有2的n次方个人,每个人会为比赛准备n首歌,每首歌有个权值xi,如果两个人比赛,xi越高的人会获胜。现在在每一轮比赛中,编号为1会与编号为2的pk,编号为3的会与编号为4的pk,每个人都想获得冠军,她们互相之间也知道相互的歌的ki,她们也都会用最优策略进行比赛。现在问最后获得胜利的人是谁。
题目分析:
这是一个挺有意思的模拟题。很明显,这个就是一个完全二叉树的形式。因此我们可以用dfs将整个图进行遍历,每到我们遍历到叶子结点时(此时左儿子编号l与右儿子编号r相差1),我们将编号为l和r的分别由小到大排序,然后我们分别对两个人的歌中二分找到是否存在大于另外一个人的最大的歌。不存在的则被淘汰,然后我们继而向根不断拓展,知道拓展到根节点就是答案。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=(1<<14)+10;
int song[maxn][20];
int n;
int dfs(int l,int r){
//printf("%d %d\n",l,r);
if(r==l+1){
sort(song[l],song[l]+n);
sort(song[r],song[r]+n);
int a=lower_bound(song[l],song[l]+n,song[r][n-1])-song[l];
int b=lower_bound(song[r],song[r]+n,song[l][n-1])-song[r];
if(a==n){
song[r][b]=0;
return r;
}
else{
song[l][a]=0;
return l;
}
}
else{
int mid=(l+r)>>1;
int x=dfs(l,mid);
int y=dfs(mid+1,r);
sort(song[x],song[x]+n);
sort(song[y],song[y]+n);
int a=lower_bound(song[x],song[x]+n,song[y][n-1])-song[x];
int b=lower_bound(song[y],song[y]+n,song[x][n-1])-song[y];
if(a==n){
song[y][b]=0;
return y;
}
else{
song[x][a]=0;
return x;
}
}
}
int main()
{
int t;
scanf("%d",&t);
int cnt=0;
while(t--){
scanf("%d",&n);
for(int i=1;i<=(1<<n);i++){
for(int j=0;j<n;j++){
scanf("%d",&song[i][j]);
}
}
cout<<"Case #"<<++cnt<<": "<<dfs(1,(1<<n))<<endl;
}
}