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;
}