湘大 XTU OJ 1308 比赛 题解:循环结束的临界点+朴素模拟

一、链接

比赛

二、题目

题目描述

有n个人要进行比赛,比赛规则如下:

  1. 假设每轮比赛的人是m,取最大的k,k=2^t且k≤m。这k个人每2人举行一场比赛,胜利者进入一下轮,失败者被淘汰。
  2. 余下的m-k个人,不进行比赛,直接进入下一轮
  3. 直到决出冠军,比赛结束。

比如有5个人参加比赛,第一轮举办2场,剩余3人进入第二轮,第二轮1场,剩余2人进入第三轮,第三轮举办1场决出冠军,所以一共要办4场比赛。 请问一共要举行几轮多少场比赛?

输入

第一行是一个整数K,表示样例的个数。 以后每行一个样例,为n(1≤n≤1000000000)

输出

每行输出两个整数,轮数和比赛场数,中间用一个空格隔开。

样例输入

复制代码
2
1
5

样例输出

复制代码
0 0
3 4

三、题意

有n个人进行比赛,最后只剩下一个人,输出比赛轮数和比赛场数,需要找到最大的小于总人数n的2的指数函数的值k

四、代码

c++

cpp 复制代码
#include<iostream>

using namespace std;

int main()
{
	int t;//表示样例数
	scanf("%d",&t);
	
	while(t--)
	{
		int n,k=1,a=0,b=0;//n表示总人数,k表示最接近n的2的指数函数的值
		//a表示轮数,b表示场数
		scanf("%d",&n);
		
		if(n<2)	printf("0 0\n");//只剩下一个人,就不需要比较,特判
		else
		{
			while(n>1)//只要不是剩下一个人,就一直循环
			{
				while(k<n)	k*=2;//寻找最接近n的2的指数函数的值
				
				if(k!=n)	k/=2;//跳出上面循环会多乘一次,所以除掉一个2
				//当然,k==n不算多乘了一次,条件判断if(k>n)也是可以的
				
				a++;//每一次算一轮
				b+=k/2;//比赛进行k/2场
				n-=k/2;//淘汰k/2个人
			}
			
			printf("%d %d\n",a,b);
		}
	}
	
	return 0;
}

c语言

cpp 复制代码
#include<stdio.h>

int main()
{
	int t;
	scanf("%d",&t);
	
	while(t--)
	{
		int n,k=1,a=0,b=0;
		scanf("%d",&n);
		
		if(n<2)	printf("0 0\n");
		else
		{
			while(n>1)
			{
				while(k<n)	k*=2;
				if(k>n)	k/=2;
				
				a++;
				b+=k/2;
				n-=k/2;
			}
			
			printf("%d %d\n",a,b);
		}
	}
	
	return 0;
}

五、总结

1.怎么找到最大的小于总人数n的2的指数函数数值k:使用一个循环,让k从1开始循环,每一次循环把k乘以2,一直到k大于n的时候跳出循环

cpp 复制代码
while(k<n)	k*=2;

这个时候需要注意一个特判:如果两个数字相等怎么办(如果总人数n是偶数)?好吧,其实是因为我审题的时候没有仔细,题目说了是k<=m,意思也就是说等于也是可以的,当然我们模拟发现也是可以的......(多此一举了)

cpp 复制代码
#include<iostream>

using namespace std;

int main()
{
	int t;//表示样例数
	scanf("%d",&t);
	
	while(t--)
	{
		int n,k=1,a=0,b=0;//n表示总人数,k表示最接近n的2的指数函数的值
		//a表示轮数,b表示场数
		scanf("%d",&n);
		
		if(n<2)	printf("0 0\n");//只剩下一个人,就不需要比较,特判
		else
		{
			while(n>1)//只要不是剩下一个人,就一直循环
			{
				while(k<=n)	k*=2;//寻找最接近n的2的指数函数的值
				
				k/=2;//跳出上面循环会多乘一次,所以除掉一个2
				//当然,k==n不算多乘了一次,条件判断if(k>n)也是可以的
				
				a++;//每一次算一轮
				b+=k/2;//比赛进行k/2场
				n-=k/2;//淘汰k/2个人
			}
			
			printf("%d %d\n",a,b);
		}
	}
	
	return 0;
}

改成这样甚至不用再多加一个条件判断,可以肯定多乘了一次2,所以直接除以一次2即可,这个就是跳出循环的临界条件,只有k>n才会跳出循环,但是这个时候k是不满足条件的,所以需要回退一次,也就是除以2

2.轮数,场数,总人数之间的关系是什么?

每一轮需要算出一个小于等于总人数n的一个最大的2的指数函数数值k

每一轮需要进行k/2场比赛

每一轮需要淘汰k/2个人

不断地更新轮数,场数,总人数,不大于总人数的最大的2的指数函数数值k即可

3.比赛最后只要留下一个冠军,也就是说总人数等于1是结束的标识,跳出循环的临界条件

六、精美图片

相关推荐
呆头鹅AI工作室13 分钟前
基于特征工程(pca分析)、小波去噪以及数据增强,同时采用基于注意力机制的BiLSTM、随机森林、ARIMA模型进行序列数据预测
人工智能·深度学习·神经网络·算法·随机森林·回归
魔法工坊38 分钟前
只谈C++11新特性 - 删除函数
java·开发语言·c++
一勺汤1 小时前
YOLO11改进-注意力-引入自调制特征聚合模块SMFA
人工智能·深度学习·算法·yolo·目标检测·计算机视觉·目标跟踪
每天写点bug1 小时前
【golang】map遍历注意事项
开发语言·算法·golang
海螺姑娘的小魏1 小时前
Effective C++ 条款 26:尽可能延后变量定义式的出现时间
开发语言·c++
w(゚Д゚)w吓洗宝宝了1 小时前
C++ 环境搭建 - 安装编译器、IDE选择
开发语言·c++·ide
程序员JerrySUN1 小时前
BitBake 执行流程深度解析:从理论到实践
linux·开发语言·嵌入式硬件·算法·架构
王老师青少年编程2 小时前
gesp(二级)(16)洛谷:B4037:[GESP202409 二级] 小杨的 N 字矩阵
数据结构·c++·算法·gesp·csp·信奥赛
robin_suli2 小时前
动态规划子序列问题系列一>等差序列划分II
算法·动态规划
机器视觉知识推荐、就业指导3 小时前
C++设计模式:解释器模式(简单的数学表达式解析器)
c++·设计模式·解释器模式