瑞士輪(noip2011普及組第三題)


題目背景

在雙人對決的競技性比賽,如乒乓球、羽毛球、國際象棋中,最常見的賽制是淘汰賽和循環賽。前者的特點是比賽場數少,每場都緊張刺激,但偶然性較高。后者的特點是較為公平,偶然性較低,但比賽過程往往十分冗長。

本題中介紹的瑞士輪賽制,因最早使用於1895年在瑞士舉辦的國際象棋比賽而得名。它可以看作是淘汰賽與循環賽的折衷,既保證了比賽的穩定性,又能使賽程不至於過長。

題目描述

2*N 名編號為 1~2N 的選手共進行R 輪比賽。每輪比賽開始前,以及所有比賽結束后,都會按照總分從高到低對選手進行一次排名。選手的總分為第一輪開始前的初始分數加上已參加過的所有比賽的得分和。總分相同的,約定編號較小的選手排名靠前。

每輪比賽的對陣安排與該輪比賽開始前的排名有關:第1 名和第2 名、第 3 名和第 4名、……、第2K – 1 名和第 2K名、…… 、第2N – 1 名和第2N名,各進行一場比賽。每場比賽勝者得1 分,負者得 0 分。也就是說除了首輪以外,其它輪比賽的安排均不能事先確定,而是要取決於選手在之前比賽中的表現。

現給定每個選手的初始分數及其實力值,試計算在R 輪比賽過后,排名第 Q 的選手編號是多少。我們假設選手的實力值兩兩不同,且每場比賽中實力值較高的總能獲勝。

輸入輸出格式

輸入格式:

輸入文件名為swiss.in 。

輸入的第一行是三個正整數N、R 、Q,每兩個數之間用一個空格隔開,表示有 2*N 名選手、R 輪比賽,以及我們關心的名次 Q。

第二行是2*N 個非負整數s1, s2, …, s2N,每兩個數之間用一個空格隔開,其中 si 表示編號為i 的選手的初始分數。 第三行是2*N 個正整數w1 , w2 , …, w2N,每兩個數之間用一個空格隔開,其中 wi 表示編號為i 的選手的實力值。

輸出格式:

輸出文件名為swiss.out。

輸出只有一行,包含一個整數,即R 輪比賽結束后,排名第 Q 的選手的編號。

輸入輸出樣例

輸入樣例#1:
2 4 2 
7 6 6 7 
10 5 20 15 
輸出樣例#1:
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。

noip2011普及組第3題。

    本人第一次寫這題的時候也是花了一些時間來理解題目(題目背景其實沒用),最后決定用排序解決。但其中有一個比較麻煩的地方,就是最后輸出的是第q名的編號,而不是分數。這就需要多一個數組來存儲編號(當然,你要用二維數組也行)。我比較常用冒泡排序,結果......七個T。經過分析,發現每次比賽后都會有n個勝者加一分,n個負者分數不變。因為每次比賽前的分數都是排好的,所以只需要多兩個數組,一個存儲勝者,一個存儲負者(這兩個數組必然是有序的),再通過歸並排序,就可以用更短的時間完成排序。前面輸入后再加一個快排,就可以了。但排序時要注意,得分相同的按編號排名,因此在排序過程中要注意別漏了這一步。程序如下。

#include<cstdio>
int n,r,q,k,a[100001],b[100001],t,c[200001],e[200001],f[200001],g[100001],h[100001],m,p,tot;
void qs(int x,int y)
{
	int i,j,v,l,z;
	i=x;
	j=y;
	z=(x+y)/2;
	v=e[z];
	l=f[z];
	do
	{
		while(e[i]>v||(e[i]==v&&f[i]<l)) i++;
		while(e[j]<v||(e[j]==v&&f[j]>l)) j--;
		if(i<=j)
		{
			tot=e[i];
			e[i]=e[j];
			e[j]=tot;
			tot=f[i];
			f[i]=f[j];
			f[j]=tot;
			i++;
			j--;
		}
	}while(i<j);
	if(j>x) qs(x,j);
	if(i<y) qs(i,y);
}
int main()
{
	int i,j=0;
	scanf("%d%d%d",&n,&r,&q);
	t=n*2;
	for(i=1;i<=t;i++) {scanf("%d",&e[i]);f[i]=i;}
	for(i=1;i<=t;i++) scanf("%d",&c[i]);
	qs(1,t);
	j=1;
	for(i=1;i<=r;i++)
	{
		m=0;
		for(j=1;j<t;j+=2)
		{
			++m;
			if(c[f[j]]<c[f[j+1]])
			{
				a[m]=e[j+1]+1;
				b[m]=e[j];
				g[m]=f[j+1];
				h[m]=f[j];
			}
			else
			{
				a[m]=e[j]+1;
				b[m]=e[j+1];
				g[m]=f[j];
				h[m]=f[j+1];
			}
		}
		for(p=1,j=1,k=0;p<=n&&j<=n;)
		{
			++k;
			if(a[p]>b[j]) {e[k]=a[p];f[k]=g[p];p++;continue;}
			if(a[p]<b[j]) {e[k]=b[j];f[k]=h[j];j++;continue;}
			if(a[p]==b[j])
			{
				if(g[p]<h[j]) {e[k]=a[p];f[k]=g[p];p++;continue;}
				else {e[k]=b[j];f[k]=h[j];j++;continue;}
			}
		}
		if(p<=n)
	 	 for(;p<=n;p++) {++k;e[k]=a[p];f[k]=g[p];}
		else
	 	 for(;j<=n;j++) {++k;e[k]=b[j];f[k]=h[j];}
	}
	printf("%d",f[q]);
}



注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com