Description
一场比赛有 2 n 2^n 2n名参赛选手,每一轮选手按顺序两两 P K PK PK,胜者进入下一轮, n n n轮后选出冠军,每位选手至多表演 n n n轮,有 n n n首不同表现力的作品,两位选手中作品表现好的晋级,每位选手都知道其他选手的作品表现力,且每次可以自主选择要表现的作品,问所有选手都采取最合理策略的前提下,谁是冠军
Input
第一行一整数 T T T表示用例组数,每组用例首先输入一整数 n n n表示比赛轮数,之后 2 n 2^n 2n行每行 n n n个整数 a i , j a_{i,j} ai,j表示这位选手准备的 n n n个作品的表现力, a i , j a_{i,j} ai,j互不相同
( 1 ≤ T ≤ 10 , 1 ≤ n ≤ 14 , 1 ≤ a i , j ≤ 1 0 9 ) (1\le T\le 10,1\le n\le 14,1\le a_{i,j}\le 10^9) (1≤T≤10,1≤n≤14,1≤ai,j≤109)
Output
输出最终获胜者的编号
Sample Input
2
1
1
2
2
1 8
2 7
3 4
5 6
Sample Output
Case #1: 2
Case #2: 4
Solution
两位选手显然谁最高分高谁赢,赢的选手显然会拿比对方最高分高的最低分去比,用 s e t set set维护每位选手剩余的分数,每次两两比较维护胜者编号即可
Code
#include<cstdio>
#include<set>
using namespace std;
#define maxn (1<<14)+5
int T,n,a[maxn];
set<int>s[maxn];
set<int>::iterator it1,it2;
int main()
{
scanf("%d",&T);
int Case=1;
while(T--)
{
scanf("%d",&n);
int N=(1<<n);
for(int i=1;i<=N;i++)
{
a[i]=i;
s[i].clear();
for(int j=0;j<n;j++)
{
int temp;
scanf("%d",&temp);
s[i].insert(temp);
}
}
for(int k=1;k<=n;k++,N/=2)
{
for(int i=1;i<=N;i+=2)
{
it1=s[a[i]].end();
it2=s[a[i+1]].end();
it1--,it2--;
if(*it1<*it2)
{
s[a[i+1]].erase(s[a[i+1]].lower_bound(*it1));
a[(i+1)/2]=a[i+1];
}
else
{
s[a[i]].erase(s[a[i]].lower_bound(*it2));
a[(i+1)/2]=a[i];
}
}
}
printf("Case #%d: %d\n",Case++,a[1]);
}
return 0;
}