鸭王的题解

一年一度的鸭子比赛开始了,有 n(n10000)n(n≤10000) 只鸭子参加了本次比赛,比赛是两两淘汰赛制。其中,第 ii 只鸭子在鸭群中的排名为 ii,如果2只鸭子的的排名之差 >k>k,一定是排名高的赢,否则不一定。

现在鸭子们已经准备好了比赛,请问可能夺冠的选手当中,排名最后的是多少号?

最难的题目

二分+贪心

// luogu-judger-enable-o2
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
bool a[18010];
vector<int>q;
int n,k;
int find(int x){
	for(int i=max(x-k,1);i<=n;i++)
		if(a[i]){
			a[i]=false;
			return i;
		}
	return -1;
}
bool check(int x){
	memset(a,1,sizeof(a));
	q.clear();
	q.push_back(x);
	a[x]=0;
	int beg=1;
	while(beg<n)
		for(int j=0;j<q.size();j++){
			beg++;
			x=find(q[j]);
			if(x==-1)return false;
			q.insert(j+q.begin()+1,x);
			j++;
		}
	return true;
}
int main(){
	cin>>n>>k; 
	int left=1,right=n+1;
	while(left+1<right){
		int mid=(left+right)/2;
		if(check(mid))left=mid;
		else right=mid;
	}cout<<left;
	return 0;
}
// luogu-judger-enable-o2
#pragma GCC optimize(3)

这个是个好东西,让我最后一个点的时间,减少了一半,从TLE变成AC

洛谷神鸭竟然用了并查集

我仔细想了一下,确实是一个好方法,在这也放一下代码

#include<bits/stdc++.h>
using namespace std;
template <typename T> inline void read(T &FF)
{
	int RR=1;FF=0;char CH=getchar();
	while(!isdigit(CH)&&CH!='-') CH=getchar();
	if(CH=='-') RR=-1;else FF=CH^48;CH=getchar();
	while(isdigit(CH)) FF=(FF<<1)+(FF<<3)+(CH^48),CH=getchar(); FF*=RR;
}
int n,k,ans;
int fa[100010];
int bcj(int xi)
{
	if(xi==-1) return xi;
	if(fa[xi]==xi) return xi;
	return fa[xi]=bcj(fa[xi]);
}
bool work(int i)
{
	for(int l=1;l<=n;l++)
		fa[l]=l;
	fa[n+1]=-1;
	fa[i]=(i==n)?-1:i+1;
	deque<int> qi; int o=1;
	qi.push_front(i);
	while(o<n)
	{
		int stp=qi.back();
		while(qi.front()!=stp)
		{
			o++;
			int pi=qi.front(); qi.pop_front(); qi.push_back(pi);
			int Ty=bcj(max(pi-k,1));
			if(Ty==-1) return false;
			qi.push_back(Ty),fa[Ty]=bcj(Ty+1);
		}
		o++;
		int pi=qi.front(); qi.pop_front(); qi.push_back(pi);
		int Ty=bcj(max(pi-k,1));
		if(Ty==-1) return false;
		qi.push_back(Ty),fa[Ty]=bcj(Ty+1);
	}
	return true;
}
int main()
{
	//freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
	read(n),read(k);
	int l=1,r=n;
	while(l<=r)
	{
		//memset(flag,0,sizeof(flag));
		int mid=(l+r)>>1;
		if(work(mid)) ans=mid,l=mid+1;
		else r=mid-1;
	}
	cout<<ans<<endl;
	return 0;
}

并查集真强大,我开 O3+O2O_3+O_2 用时还是他的代码的10倍左右

原文地址:https://www.cnblogs.com/zhaohaikun/p/12816951.html