1 条题解
-
0
题目分析
我们需要处理一个蛋糕分段问题:每次将最右边的偶数长度蛋糕段对半切分,直到所有段长度都为奇数。然后回答第 段蛋糕的长度。
关键观察
- 数学性质:任何偶数都可以表示为 的形式,其中 是奇数
- 切分规律:长度为 的蛋糕段最终会被切分成 段长度为 的蛋糕
- 前缀和定位:通过前缀和可以快速定位第 段属于哪个原始蛋糕段
算法思路
1. 预处理阶段
对于每个原始蛋糕段 :
- 不断除以 2 直到得到奇数
- 记录切分次数 ,则该段会被切分成 段
- 计算前缀和
2. 查询阶段
对于每个查询 :
- 使用二分查找在前缀和数组中找到第一个 的位置
- 答案就是 (该位置对应的奇数长度)
代码实现
#include <iostream> #include <algorithm> using namespace std; typedef long long ll; const int N = 2e5 + 5; int n, cnt[N], a[N]; ll s[N]; int main() { cin >> n; for (int i = 1; i <= n; i++) { cin >> a[i]; cnt[i] = 1; // 分解为 2^k * 奇数的形式 while (a[i] % 2 == 0) { a[i] /= 2; cnt[i] *= 2; } s[i] = s[i - 1] + cnt[i]; // 前缀和 } int q; cin >> q; while (q--) { ll x; cin >> x; // 二分查找定位 int pos = lower_bound(s + 1, s + n + 1, x) - s; cout << a[pos] << '\n'; } return 0; }
算法正确性
以样例1为例:
- 分解后:
- → 切分成2段长度为7
- → 切分成1段长度为9
- → 切分成8段长度为1
- → 切分成4段长度为3
- 前缀和:
- 查询 时,找到 ,答案为
复杂度分析
- 预处理:,每个数最多除 次
- 每次查询:,二分查找
- 总复杂度:
算法优势
- 避免显式模拟:通过数学分析直接计算结果
- 高效查询:利用前缀和和二分快速定位
- 处理大数据:支持 达到 的查询
该算法巧妙利用了问题的数学性质,将复杂的切分过程转化为简单的数学计算,实现了高效求解。
- 1
信息
- ID
- 3323
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者