https://www.luogu.org/problemnew/show/P1309

看到题目,先想到每局sort一次,简单但一定会超时。然后想到,在一个2*n的有序数组里,每次只有n个元素+1,一定有高效的方法。想到如果用链表或者数组模拟链表,对于每局比赛,输的不管,赢得还保持原来的相对顺序,故在链表从前往后扫一遍,依次把递增的元素排到正确的位置,这样可以实现每局比赛o(n),但是非常难写。

看题解,用到了归并排序的思想。假设每局比赛之前数组已经排好序,那么对于这局比赛赢的人来说,他们重排后在数组中的相对位置不变,对输的人也是,故开一个辅助数组,分别记录本局输和赢的人的相对顺序,然后依次比较输和赢的最前的人,合并到原数组中,这样就实现了o(n)排序。

代码不大好写时,在纸上列出需要用的变量数组函数什么的,以及他们的功能,思路理清了代码逻辑也就搞好了,很快就写出来了,而且bug率低且易调试。

#include<cstdio>
#include<algorithm>
using namespace std;

int n,r,q;
int s[200005],que2[200005],w[200005];
int p,p1,p2;
int que[200005];

bool cmp(int x,int y)
{
	if(s[x]!=s[y])return s[x]>s[y];
	return x<y;
}

int main()
{
	freopen("input.in","r",stdin);
	scanf("%d%d%d",&n,&r,&q);
	for(int i=1;i<=2*n;i++)scanf("%d",&s[i]);
	for(int i=1;i<=2*n;i++)scanf("%d",&w[i]);
	
	for(int i=1;i<=2*n;i++)que[i]=i;
	sort(que+1,que+1+2*n,cmp);
	while(r--)
	{
		p1=0;p2=n;
		for(int i=2;i<=2*n;i+=2)
		{
			if(w[que[i-1]]>w[que[i]])
			{
				que2[++p1]=que[i-1];
				que2[++p2]=que[i];
			}
			else
			{
				que2[++p1]=que[i];
				que2[++p2]=que[i-1]; 
			}
		}
		for(int i=1;i<=n;i++)s[que2[i]]++;
		
		p=1;p1=1;p2=n+1;
		for(int i=1;i<=2*n;i++)
		{
			if(p2>2*n)que[p++]=que2[p1++];
			else if(p1>n)que[p++]=que2[p2++];
			else if(cmp(que2[p1],que2[p2]))que[p++]=que2[p1++];
			else que[p++]=que2[p2++];
		}
	}
	
	printf("%d\n",que[q]);
	return 0;
}