NOIP2011瑞士轮

本文介绍了NOIP2011年瑞士轮比赛的算法问题,指出初始暴力解决方法虽然可行但效率较低,仅能得到50分。通过分析比赛规则,作者提出利用归并排序的思想优化解决方案,将选手分为胜者组和败者组,保持分数顺序,从而实现更高效的算法。文章提供了模拟比赛、记录、归并的程序代码,提醒注意数据量大时的读入优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目来自网上(2333)




乍眼一看这道题好像很水,其实——的确很水。这其实只是一道普及组的题目而已啦。但我能一遍过还是很开森的。

暴力的话,每次处理完就sort一次,感觉很不错。但根据官方的数据这只有50分,因为复杂度是O(Rnlogn)的(n是2倍N)。

其实在心里想想就能想通,每次比赛总是排名相邻的两人比赛,赢着加分,输者不加不减。我们先sort一次,然后每次把选手分为两组——胜者组和败者组。我们就可以发现,两组的分数顺序还是有序的。恍然大悟!——归并排序!

于是就手打一遍,模拟胜负,记录,归并,循环R次即可。由于数据比较大,建议开读入优化。

下面标程双手奉上(写的有点丑):

#include	<iostream>
#include	<cstdio>
#include	<cstdlib>
#include	<cstring>
#include	<algorithm>
using namespace std;
int N,n,R,Q,win[100001],lose[100001],wini,losei,ki;
struct node
{
	int s,w,num;
}f[200001],k[200001];
bool cmp(node a,node b)
{
	return a.s>b.s ||(a.s==b.s && a.num<b.num);
}
int gi()
{
	int x=0;char ch=getchar();
	while(ch<'0' || ch>'9')ch=getchar();
	while(ch>='0' && ch<='9')x=x*10+ch-48,ch=getchar();
	return x;
}
int main()
{
	N=gi();n=N*2;R=gi();Q=gi();
	for(int t=1;t<=n;t++)
	  {
	  		f[t].s=gi();
	  		f[t].num=t;
	  }
	for(int t=1;t<=n;t++)
	  {
	  		f[t].w=gi();
	  }
	sort(f+1,f+n+1,cmp);
	while(R--)
	{
		wini=losei=1;
		for(int tt=1;tt<=n;tt+=2)
		  {
		  		if(f[tt].w>f[tt+1].w)f[tt].s+=1,win[wini++]=tt,lose[losei++]=tt+1;
		  		else f[tt+1].s+=1,win[wini++]=tt+1,lose[losei++]=tt;
		  }
		wini=losei=ki=1;
		while(wini<=N && losei<=N)
		{
				if((f[win[wini]].s>f[lose[losei]].s) || (f[win[wini]].s==f[lose[losei]].s && f[win[wini]].num<f[lose[losei]].num))
					k[ki++]=f[win[wini++]];
				else k[ki++]=f[lose[losei++]];
		}
		while(wini<=N)
		k[ki++]=f[win[wini++]];
		while(losei<=N)
		k[ki++]=f[lose[losei++]];
		for(int ii=1;ii<=n;ii++)
		f[ii]=k[ii];
	}
	printf("%d",f[Q].num);
	return 0;
}
如上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值