[CP / Codeforces] E. Vlad and an Odd Ordering(Div. 4)
我很喜欢这道题,第一是因为它对我来说很难,第二是因为它体现了数学中的一些美妙而神奇的性质。惭愧的是,初见时我并没能做出来,看了 editorial 后也似懂非懂,直到两个星期之后,才总算理清楚思路,并且给出了一种略微复杂的解法——不知道和官方题解是否重合。
题目大意是,你有标着
- 首先从小到大摆放所有标着奇数的卡片;
- 然后从小到大摆放所有标着奇数
的卡片; - 然后从小到大摆放所有标着奇数
的卡片; - ……
- 直到所有卡片都被摆放完毕。
问第
观察数据规模,如果暴力模拟的话必然会超时,所以需要研究其背后的规律。
定义第
- 第 1 轮:
- 第 2 轮:
- 第 3 轮:
- 第 4 轮:
- 第 5 轮:
- 第 6 轮:
- 第 7 轮:
- 第 8 轮:
注意到只有
首先,第一轮摆放的必定是所有的奇数,这意味着除
观察第
更一般地,我们会发现,所有满足
因此得出结论,只有在轮次为
每个轮次摆放的数字总个数可以通过以下方法获得:
- 计算
得到每一轮所乘的最大奇数 - 如果
是偶数,则将其减一 - 再通过
得到该轮所乘奇数的总个数,也即该轮摆放的数字个数
因此得到代码:
代码 1( )
void solve() { int n, k; std::cin >> n >> k; int cnt = 0, w = 1, t; while (1) { t = n / w; t -= !(t & 1); t = (t + 1) / 2; if (cnt + t >= k) break; cnt += t; w <<= 1; } std::cout << ((k - cnt) * 2 - 1) * w << '\n'; }
官方题解提供了两种做法:第一种和我的解法类似,第二种采用了更为简洁的递归,但原理和前面其实是相同的,代码附在下面。
代码 2( )
int dfs(int n, int k) { if (k <= (n + 1) / 2) { return k * 2 - 1; } return 2 * dfs(n / 2, k - (n + 1) / 2); } void solve() { int n, k, ans = 0; std::cin >> n >> k; std::cout << dfs(n, k) << '\n'; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)