节操大师 北方大学生程序设计竞赛 南开大学

Description

MK和他的小伙伴们(共n人,且保证n为2的正整数幂)想要比试一下谁更有节操,于是他们组织了一场节操淘汰赛。他们的比赛规则简单而暴力:两人的节操正面相撞,碎的一方出局,而没碎的一方晋级(脑补一下端午节的碰鸡蛋游戏>_<)。最后经过数轮淘汰决出冠军“节操大师”。

通过理性的研究,你测算出他们的节操值分别为1,2,...,n,我们不妨称这个值为“硬度”吧。同时你又测出了一个节操常数k:当两个硬度相差超过k的节操相撞时,硬度小的节操必碎;而当两个硬度相差不超过k的节操相撞时,由于现场操作的不确定因素,两个节操都有碎的可能(当然我们假设不会出现两边都碎的情况囧)。

显然,节操值较低的人也许没有任何可能得到冠军。下面就请你预测,这次比赛的冠军“节操大师”的节操最小值为多少。

Input

输入只有一行,两个正整数n和k分别表示参赛人数和节操常数。

Output

输出一行,一个正整数,表示“节操大师”的节操最小值。

Sample Input

8 2

Sample Output

3

Hint

对20%数据,n≤16;

对50%数据,n≤4096;

对100%数据,n≤131072, 保证n为2的正整数幂,k<n。

Source

Nankai UniversityFreshman Programming Contest 2015


题解:这道题目很有意思,两两相撞,当节操差大于k时,节操小的必碎,否则的话,两个都可能碎(一次碰撞只能碎一个)

我们采用二分答案的方法,对于每一个答案ans,我们判断它能否形成一个竞赛树(自顶向下生成,也就是逆向思考)在考虑最后一轮对撞的时候

必然有ans与x对撞,其中ans >= x 或者是x - ans <= k因为只有这样才有可能选上,我们贪心地对于ans选取比ans大,且ans可能战胜的最大的x,如果不满足的话,我们就选取第二大的x。。。。依次类推,这样的话我们可以保证ans总是发挥了它最大的能力,这样的话最有可能构成一个完全二叉树,如果不能构成完全二叉树,说明这个答案不合适


#include <iostream>
#include <set> 
#include <cstdio>
#include <vector>
using namespace std;
int n,k;
bool check(int x)
{
	set<int> st;
	vector<int> vec;
	vec.push_back(-x);
	for(int i = 1;i <= n;i++)
		if(i != x)
			st.insert(-i);
	while(vec.size() != n){
		int s = vec.size();
		for(int i = 0;i < s;i++){
			int v = vec[i];
			auto np = st.lower_bound(v - k);
			int y = *np;
			if(np != st.end()){
				vec.push_back(y);//
				st.erase(y);
			}
			else
				return false;
		}
	}
	return true;
}
int main()
{
	scanf("%d%d",&n,&k);
	int l = 1,r = n + 1;
	while(l < r)
	{
		int mid = (l+r)/2;
		if(!check(mid)) l = mid + 1;
		else r = mid ;
	}
	cout<<l<<endl;
} 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值