A Singing Contest
https://www.cnblogs.com/longl/p/9424539.html
思路:
由于每个选手的策略略都是尽可能赢,所以他该认输的时候只能认输。能赢的时候只要选权值大于对方最大值的最小值,大的留在后面不会更差,直接模拟即可。
我的模拟方法是:开一个二维的vector,第一维表示比赛场次,每次比赛完把结果保存到下一层,第二维表示每个歌手(注意不要开小了,我因为开小了TLE好几发,2^14 =16384 )。
在将结果记录到下一层的同时还要记录原有歌手的标号,以便最后输出结果。
代码:
#include
using namespace std;
const int maxn = 20000;
vector vec[20][maxn];///第一维表示比赛场次,第二维代表歌手
int id[maxn],v, tmp[maxn];
void init()
{
for(int i=0;i<20;i++)
for(int j=0;j<maxn;j++)
vec[i][j].clear();
}
int main()
{
// printf("%d\n",1<<14);
int t;
scanf("%d",&t);
for(int cas=1;cas<=t;cas++){
int n;
init();
scanf("%d",&n);
int cnt = 1<<n;
for(int i=1;i<=cnt;i++){
for(int j=1;j<=n;j++){
scanf("%d",&v);
vec[1][i].push_back(v);
}
}
for(int i=1;i<=cnt;i++)id[i]=i;
int singer = cnt;
for(int i=1;i<n;i++){
for(int j=1;j<=singer;j+=2){
set st1,st2;
set::iterator it;
for(int k=0;k<vec[i][j].size();k++)st1.insert(vec[i][j][k]);
for(int k=0;k<vec[i][j+1].size();k++)st2.insert(vec[i][j+1][k]);
int v1=*(--st1.end()); ///歌手1的最大值
int v2=*(--st2.end()); ///歌手2的最小值
if(v1>v2){
st1.erase( st1.lower_bound(v2) ); ///在v1中找到比v2大的最小值
for(it=st1.begin();it!=st1.end();it++) ///复制到下一层
vec[i+1][(j+1)/2].push_back(*it);
tmp[(j+1)/2]=id[j]; ///保存原有id
}else{
st2.erase( st2.lower_bound(v1) ); /// ///在v2中找到比v1大的最小值
for(it=st2.begin();it!=st2.end();it++)
vec[i+1][(j+1)/2].push_back(*it);
tmp[(j+1)/2]=id[j+1]; ///保存原有id
}
}
singer>>=1;
for(int j=1;j<=singer;j++)
id[j]=tmp[j];
}
int ans=0;
if(vec[n][1][0]>vec[n][2][0]) ans = id[1];
else ans=id[2];
printf("Case #%d: %d\n",cas,ans);
}
return 0;
}
