开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第23天,点击查看活动详情
题目描述
给定一个队列,初始时队列为空。
首先,依次从队尾插入 a、b、c、d、e 五个元素。
随后,不断重复以下操作:
- 设当前队头元素为 x。
- 依次从队尾插入两个 x。
- 将队头元素 x 弹出队列。
例如,第 1 轮操作过后,队列变为 b、c、d、e、a、a,第 1 个被弹出队列的元素为 a;第 2 轮操作过后,队列变为 c、d、e、a、a、b、b,第 2 个被弹出队列的元素为 b;第 3 轮操作过后,队列变为 d、e、a、a、b、b、c、c,第 3 个被弹出队列的元素为 c......
请你计算并输出第 n 个被弹出队列的元素。
输入格式
一个整数 n。
输出格式
输出第 n 个被弹出队列的元素。
数据范围
前 个测试点满足 。
所有测试点满足 。
输入样例1:
1
输出样例1:
a
输入样例2:
6
输出样例2:
a
思路分析
- 这是79周赛的第一题,可以说是非常简单了,首先要想想 的数据,如果说直接暴力循环的话无疑是会爆炸的,所以我们要使用优化的数组
- 优化数组采用二进制优化来做
- 我们需要两个数组,一个数组用来存放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:代码写得有点丑,大家不要介意~