瑞士轮

本文详细解析了一道NOIP竞赛题目,通过优化算法从O(nrlogn)的时间复杂度降低到O(n(logn+r)),介绍了如何利用归并排序处理比赛结果,实现胜者组与败者组的有效合并。

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

蒻苟经过一个小时的鏖战终于拿下这道题
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,r,q;
struct nod{
	int sco;
	int num;
	int ab;
}a[1000005];
struct fuck{
	int sco;
	int num;
	int ab;
}win[1000005];
struct node{
	int sco;
	int num;
	int ab;
}lose[1000005];
bool pk(int a,int b)
{
	if (a>b)
	{
		return true;
	}
	return false;
}
bool cmp(nod x,nod y)
{
	if (x.sco==y.sco)
	{
		return x.num < y.num;
	}
	return x.sco > y.sco;
}
int main()
{
	memset(win,-1,sizeof(win));
	memset(lose,-1,sizeof(lose));
	scanf("%d%d%d",&n,&r,&q);
	n*=2;
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&a[i].sco);
	}
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&a[i].ab);
	}
	for (int i=1;i<=n;i++)
	{
		a[i].num=i;
	}
	sort(a+1,a+n+1,cmp);
	for (int i=1;i<=r;i++)
	{
		int k=-1;
		while (k+2<n)
		{
			k+=2;
			
			if (pk(a[k].ab,a[k+1].ab))
			{
				a[k].sco++;
				win[k/2+1].num=a[k].num;
				win[k/2+1].sco=a[k].sco;
				win[k/2+1].ab=a[k].ab;
				lose[k/2+1].num=a[k+1].num;
				lose[k/2+1].sco=a[k+1].sco;
				lose[k/2+1].ab=a[k+1].ab;
				continue;
			}
			a[k+1].sco++;
			win[k/2+1].num=a[k+1].num;
			win[k/2+1].sco=a[k+1].sco;
			win[k/2+1].ab=a[k+1].ab;
			lose[k/2+1].num=a[k].num;
			lose[k/2+1].sco=a[k].sco;
			lose[k/2+1].ab=a[k].ab;
		}
		int w=1;
		int l=1;
		for (int j=1;j<=n;j++)
		{
			if (win[w].sco>lose[l].sco)
			{
				a[j].num=win[w].num;
				a[j].sco=win[w].sco;
				a[j].ab=win[w].ab;
				w++;
				continue;
			}
			else if (win[w].sco==lose[l].sco)
			{
				if (win[w].num<lose[l].num)
				{
					a[j].num=win[w].num;
					a[j].sco=win[w].sco;
					a[j].ab=win[w].ab;
					w++;
				}
				else 
				{
					a[j].num=lose[l].num;
					a[j].sco=lose[l].sco;
					a[j].ab=lose[l].ab;
					l++;
				}
				continue;
			}
			a[j].num=lose[l].num;
			a[j].sco=lose[l].sco;
			a[j].ab=lose[l].ab;
			l++;
		}
	}
	printf("%d",a[q].num);
	return 0;
	
}

暴力算法的话 很简单 每次进行sort排序 时间复杂度为o(nrlogn)

以下附上暴力算法

#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
struct xs{
	int score;
	int num;
	int power;
	bool operator < (const xs b)const
	{
		if(score == b.score)return num < b.num;
		else return score > b.score;
	}
}a[100005];
int N,R,Q;
int main()
{	
	//freopen("swiss.in","r",stdin);
	//freopen("swiss.out","w",stdout);
	scanf("%d%d%d",&N,&R,&Q);
	for(int i = 1 ; i<= 2*N ;i++)
	{
		scanf("%d",&a[i].score);
		a[i].num=i;
	}
		for(int i = 1 ; i<= 2*N ;i++)
	{
		scanf("%d",&a[i].power);
	}
	for(int i = 1; i <=R ; i++)
	{
		sort(a+1,a+1+2*N);
		for(int j = 1 ;j <= N ; j++)
		{
			if(a[2*j].power<a[2*j-1].power)
			a[2*j-1].score++;
			else
			a[2*j].score++;
		}
	
	}	
	sort(a+1,a+1+2*N);
	printf("%d",a[Q].num);
	
}


为了获得满分(装x)

很明显 每次比赛结束 都会产生有序的胜者组和败者组 

有序的原因是 在上一次排序基础上 不管是胜者组还是败者组 分数相对没有发生变化 也就是说 将比赛的结果重新分组 可以得到两个有序数组

有序数组又有什么用呢 

很明显 用归并排序 将胜者组和败者组重新排列

这样得到时间复杂度为o(n(logn+r))

成功AC




2019年8月22日 多云

距noip考试还有80天

❤Zy


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值