瑞士轮(归并)

原题链接:http://icpc.upc.edu.cn/problem.php?cid=2691&pid=0

2*N名编号为1~2N的选手共进行R轮比赛。每轮比赛开始前,以及所有比赛结束后,都会对选手进行一次排名。排名的依据是选手的总分。选手的总分为第一轮开始前的初始分数加上已参加过的所有比赛的得分和。总分相同的,约定编号较小的选手排名靠前。
每轮比赛的对阵安排与该轮比赛开始前的排名有关:第1名和第2名、第3名和第4名、……、第2K – 1名和第2K名、…… 、第2N – 1名和第2N名,各进行一场比赛。每场比赛胜者得1分,负者得0分。也就是说除了首轮以外,其它轮比赛的安排均不能事先确定,而是要取决于选手在之前比赛中的表现。
现给定每个选手的初始分数及其实力值,试计算在R轮比赛过后,排名第Q的选手编号是多少。我们假设选手的实力值两两不同,且每场比赛中实力值较高的总能获胜。

输入

输入的第一行是三个正整数N、R、Q,每两个数之间用一个空格隔开,表示有2*N名选手、R轮比赛,以及我们关心的名次Q。

第二行是2*N个非负整数s1, s2, …, s2N,每两个数之间用一个空格隔开,其中si表示编号为i的选手的初始分数。

第三行是2*N个正整数w1, w2, …, w2N,每两个数之间用一个空格隔开,其中wi表示编号为i的选手的实力值。

输出
输出只有一行,包含一个整数,即R轮比赛结束后,排名第Q的选手的编号。

样例输入

2 4 2
7 6 6 7
10 5 20 15

样例输出

1

对于 30%的数据,1 ≤ N≤ 100;

对于 50%的数据,1 ≤ N≤ 10,000;

对于 100%的数据,1 ≤ N≤ 100,000,1 ≤ R≤ 50,1 ≤ Q≤ 2N,0 ≤ s1, s2, …, s2N ≤ 10^8,1 ≤ w1,w2, …, w2N ≤ 10^8。

刚开始看到这题的时候肯定是想着用sort排,很简单,但是提交上去就是超时,可能是因为数太多了,排的次数也多。

分析:分析之后不难发现,当每场比赛结束的时候,他们之间的顺序是没怎么变化的,也就是说大致顺序没变,变的只是两个之间或相邻的前后几个,那是否可以分别将胜者和负者各自存在一个数组里,再将两个数组归并呢?这样时间复杂度是不是就减少很多了?

思路:在每场比赛后,将胜者和负者分别存进两个数组,再归并;

ACcode:

#include<bits/stdc++.h>
using namespace std;
int n,r,m;
const int N=200010;

struct T{
	int id,sc,st;
}a[N],win[N],fa[N];

int cmp(T x,T y)
{
	if(x.sc!=y.sc) return x.sc>y.sc;
	return x.id<y.id;
}

void merge(T a[N],T win[N],T f[N])	//将两个排序数组归并到一个数组里; 
{
	int i=1,j=1,k=1;
	while(i<=n/2&&j<=n/2)
	{
		if(win[i].sc>fa[j].sc)
		{
			a[k]=win[i],i++,k++;
		}
		else if(win[i].sc<fa[j].sc)
		{
			a[k]=fa[j],j++,k++;
		}
		else	//分数相等,看编号;
		{
			if(win[i].id<fa[j].id)
			{
				a[k]=win[i],i++,k++;
			}
			else 
			{
				a[k]=fa[j],j++,k++;
			}
		}
	}
	while(i<=n/2)	//剩下的存进去;
	{
		a[k]=win[i],k++,i++;
	}
	while(j<=n/2)
	{
		a[k]=fa[j],k++,j++;
	}
}
int main(){
	scanf("%d%d%d",&n,&r,&m);
	n*=2;
	for(int i=1;i<=n;i++) scanf("%d",&a[i].sc),a[i].id=i;
	for(int i=1;i<=n;i++) scanf("%d",&a[i].st);
	sort(a+1,a+1+n,cmp);	//第一轮前排序; 
	for(int i=1;i<=r;i++)
	{
		
		int x=1,y=1;
		for(int i=1;i<=n;i+=2)
		{
			if(a[i].st>a[i+1].st)
			{
				a[i].sc++;
				win[x++]=a[i];	//胜者存到win数组; 
				fa[y++]=a[i+1];	//负者存到fa数组; 
			}
			else
			{
				a[i+1].sc++;
				win[x++]=a[i+1];
				fa[y++]=a[i];
			}
		}
		merge(a,win,fa);	//归并win数组,fa数组到a数组; 
	}
	//sort(a+1,a+1+n,cmp); 
	printf("%d",a[m].id);
	return 0; 
} 
如果对归并不太熟的化建议看一下归并排序的模板

有什么不对的或者不懂的地方欢迎留言讨论ya;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值