编码升序排序后,每个询问从左往右找第一个满足 code % 10^k == b 的编码,首个命中即最小答案。
OJ: roj
题目 ID: 3645
难度:普及-
标签:模拟排序数学
创建: 2026-10-02 12:32
更新: 2026-10-06 15:50
题目描述
图书馆中每本书有正整数编码。给出 5 5 / 2123 1123 23 24 24 / 2 23 / 3 123 / 3 124 / 2 12 / 2 12,输出 23 / 1123 / -1 / -1 / -1。数据范围:
思路
把图书编码升序排序,再在有序数组里从左往右找第一个满足 code % 10^k == b 的编码,首个命中即候选中的最小者。用需求码长度决定模数
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-10-02 12:32
# update_at: 2026-10-02 12:32
import sys
pow10 = [1] * 8 # pow10[k] = 10**k,用来按长度截取编码的末 k 位
def build_pow10() -> None:
"""预处理 10 的幂:需求码长度 ≤ 7,取末 k 位只需要这张小表。"""
for k in range(1, 8):
pow10[k] = pow10[k - 1] * 10
def best_suffix_match(codes: list[int], queries: list[tuple[int, int]]) -> list[int]:
"""对每个询问 (长度 k, 需求码 need) 返回以 need 结尾的最小图书编码,不存在为 -1。
编码按从小到大排好后从左往右扫,命中的第一个后缀就是最小答案,
于是每个询问只需在有序编码里做一次顺序查找,O(n) 回答。
"""
return [
next((code for code in codes if code % pow10[k] == need), -1) # 首个匹配即最小
for k, need in queries
]
def solve() -> None:
build_pow10()
data = iter(map(int, sys.stdin.buffer.read().split()))
n, q = next(data), next(data)
codes = sorted(next(data) for _ in range(n)) # 排序让「首个命中 = 最小答案」成立
queries = [(next(data), next(data)) for _ in range(q)]
print('\n'.join(map(str, best_suffix_match(codes, queries))))
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-06 15:50
* update_at: 2026-10-06 15:50
*/
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long ll;
const int MAXN = 1005; // 图书数量上限
ll code[MAXN]; // 升序排序后的图书编码
ll pow10[10]; // pow10[k] = 10^k,用来截取末 k 位
int main() {
pow10[0] = 1;
for (int k = 1; k <= 8; k++) {
pow10[k] = pow10[k - 1] * 10;
}
ll n, q;
cin >> n >> q;
for (int i = 0; i < n; i++) {
cin >> code[i];
}
sort(code, code + n); // 排序后「第一个命中」就是最小的编码
for (int i = 0; i < q; i++) {
ll len, need;
cin >> len >> need;
ll ans = -1;
for (int j = 0; j < n; j++) {
// 编码末 len 位等于需求码,即对 10^len 取模相等
if (code[j] % pow10[len] == need) {
ans = code[j];
break;
}
}
cout << ans << "\n";
}
return 0;
}