1 条题解
-
0
题解:构造能被B-1整除的最大B进制数
问题分析
题目要求在给定基数B下,使用给定数量的数字卡片,构造一个能被B-1整除的最大数,并回答关于该数特定位置的查询。核心挑战在于:
- 利用B进制数的整除特性(能被B-1整除等价于各位数字和能被B-1整除)
- 构造最大数(尽可能多的数字,且高位数字尽可能大)
- 高效处理大规模查询(位置可能达1e18)
关键 insights
- 整除特性:对于基数B,任何数 mod (B-1) 等于其各位数字和 mod (B-1)。因此,只需保证数字和能被B-1整除即可。
- 最大数构造策略:
- 优先使用所有可用数字(数量最多)
- 若数字和不能被B-1整除,移除最小的必要数字(使剩余和能被B-1整除)
- 剩余数字按降序排列(确保高位最大)
- 查询处理:通过前缀和+二分查找,快速定位任意位置的数字,避免存储完整大数。
算法步骤
-
计算总和与总数:
- 计算所有数字的总和S和总数量T
- 计算S mod (B-1) 得到余数R
-
调整数字集:
- 若R=0:直接使用所有数字
- 若R≠0:移除一个数字x(x≡R mod (B-1)),优先选择最小的x(减少对大数构造的影响)
-
预处理有效数字:
- 保留数量>0的数字,按降序排列
- 计算前缀和数组,用于快速定位位置
-
处理查询:
- 对于位置k:若k≥总位数,返回-1
- 否则计算k在降序序列中的偏移量,通过二分查找前缀和定位对应数字
代码实现
#include <bits/stdc++.h> using namespace std; int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); int B, q; cin >> B >> q; vector<long long> a(B); for (int i = 0; i < B; ++i) { cin >> a[i]; } // 计算数字总和S和总数量T long long S = 0; long long T = 0; for (int i = 0; i < B; ++i) { S += 1LL * i * a[i]; T += a[i]; } int M = B - 1; int R = S % M; if (R < 0) R += M; // 确保余数非负 // 确定需要移除的数字x_remove bool need_remove = (R != 0); int x_remove = -1; if (need_remove) { // 优先找x ≡ R mod M且x >= R(最小可能的x) for (int x = R; x < B; x += M) { if (a[x] > 0) { x_remove = x; break; } } // 若未找到,找x = R - M(等价于x ≡ R mod M) if (x_remove == -1) { x_remove = R - M; } } // 预处理有效数字及其前缀和 vector<int> digits; // 降序存储有效数字 vector<long long> prefix; // 前缀和数组 long long total = 0; // 总位数 for (int d = B - 1; d >= 0; --d) { long long cnt = a[d]; if (need_remove && d == x_remove) { cnt -= 1; // 移除一个x_remove } if (cnt > 0) { digits.push_back(d); total += cnt; prefix.push_back(total); } } // 处理全零特殊情况(仅保留一个0) bool all_zero = true; for (int d : digits) { if (d != 0) { all_zero = false; break; } } if (all_zero) { digits = {0}; prefix = {1}; total = 1; } // 处理查询 while (q--) { long long k; cin >> k; if (k >= total) { cout << -1 << '\n'; continue; } // 计算在降序序列中的索引(从左到右) long long idx = total - 1 - k; if (all_zero) { cout << 0 << '\n'; continue; } // 二分查找定位数字 auto it = upper_bound(prefix.begin(), prefix.end(), idx); int pos = it - prefix.begin(); cout << digits[pos] << '\n'; } return 0; }
复杂度分析
- 时间复杂度:O(B + q log C),其中B为基数,q为查询数,C为有效数字种类数(C ≤ B)
- 空间复杂度:O(B),用于存储数字计数和前缀和数组
该方案高效处理了大规模输入和查询,通过数学特性优化构造逻辑,结合二分查找实现快速查询响应。
- 1
信息
- ID
- 3546
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者