Acwing第79场周赛-4723. 队列

82 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第23天,点击查看活动详情

题目描述

给定一个队列,初始时队列为空。

首先,依次从队尾插入 abcde 五个元素。

随后,不断重复以下操作:

  1. 设当前队头元素为 x。
  2. 依次从队尾插入两个 x。
  3. 将队头元素 x 弹出队列。

例如,第 1 轮操作过后,队列变为 bcdeaa,第 1 个被弹出队列的元素为 a;第 2 轮操作过后,队列变为 cdeaabb,第 2 个被弹出队列的元素为 b;第 3 轮操作过后,队列变为 deaabbcc,第 3 个被弹出队列的元素为 c......

请你计算并输出第 n 个被弹出队列的元素。

输入格式

一个整数 n。

输出格式

输出第 n 个被弹出队列的元素。

数据范围

前 55 个测试点满足 1n101≤n≤10
所有测试点满足 1n1091≤n≤10^9

输入样例1:

1

输出样例1:

a

输入样例2:

6

输出样例2:

a

思路分析

  • 这是79周赛的第一题,可以说是非常简单了,首先要想想 10910^9 的数据,如果说直接暴力循环的话无疑是会爆炸的,所以我们要使用优化的数组
  • 优化数组采用二进制优化来做
    • 我们需要两个数组,一个数组用来存放5×2的n次方,这是一个循环的标准数组
    • 另一个就是前缀和数组,存放的是标准数组的前n项的和
    • 前缀和数组用来判断n在哪个区间内
  • 再就是当n判断出了在哪个区间后,我们需要的是区间下标cnt和n在这个区间内还有多大的数
  • 但是要注意的是,取模是会取到0的,而当n小于等于5的时候由于底数为1,所以取模是1、2、3、4、5,那么对于≤5的数要进行特判

代码如下

#include<iostream>
#include<cmath>
using namespace std;

typedef long long LL;
const int N = 30;
LL a[N];
LL s[N];//前缀和


int main()
{
	char temp[5] = { 'a','b','c','d','e' };
	int n;
	cin >> n;
	int res = 5;
	for (int i = 1; i < 29; i++) {
		a[i] = res;
		s[i] = s[i - 1] + res;
		res *= 2;
	}
	int cnt = 0, value = 0;
	for (int i = 1; i < 29; i++) {
		if (n < s[i]) {
			cnt = i;
			value = n - s[i - 1];
			break;
		}
	}
	if (n <= 5) {
		cout << temp[n - 1];
	}
	else
		cout << temp[(int)(value / pow(2, cnt - 1))];
	return 0;
}

PS:代码写得有点丑,大家不要介意~