Official
C - 商品検索システム / Product Search System Editorial
by
C - 商品検索システム / Product Search System Editorial
by
MMNMM
この問題は、いわゆる Successor/Predecessor を高速に求めることができれば、連想配列などを使って解くことができます。
より具体的には、与えられた \(X\) に対して
- \(X\le V _ i\) を満たす最小の \(V _ i\)
- \(X\ge V _ i\) を満たす最大の \(V _ i\)
- これらの \(V _ i\) に対する \((i,S _ i)\) の一覧もしくはそのうち \(i\) が最小のもの
を高速に求められればよいです。 これは、\(V _ i\) をソート済み列や平衡二分探索木など、\(V\) と対応する \((i,S _ i)\) の列を連想配列などで管理することで求めることができます。 連想配列を平衡二分探索木で実現している場合、これらをまとめることもできます。
実装例は以下のようになります。
#include <iostream>
#include <vector>
#include <map>
#include <ranges>
using namespace std;
int main() {
int N, Q;
cin >> N >> Q;
// V[i] と対応する (i, S[i]) の列
map<int, vector<pair<int, string>>> merchandise;
for (int i = 0; i < N; ++i) {
string S;
int V;
cin >> S >> V;
merchandise[V].emplace_back(make_pair(i, S));
}
for (int i = 0; i < Q; ++i) {
int X;
cin >> X;
// X = V[i] となる V[i] が存在すれば
if (merchandise.contains(X)) {
// S をすべて出力
for (string S : merchandise[X] | views::values) {
cout << S << " ";
}
cout << endl;
} else { // 存在しなければ
// X 以上のうち最小の V[i] を求めて
auto it = merchandise.lower_bound(X);
// 大小関係をもとに場合分け
if (it == merchandise.begin() || (it != merchandise.end() && prev(it)->first + it->first < 2 * X)) {
cout << it->second[0].second << endl;
} else if (it == merchandise.end() || it->first + prev(it)->first > 2 * X) {
cout << prev(it)->second[0].second << endl;
} else { // 距離が等しければ番号が小さいほう
cout << min(it->second[0], prev(it)->second[0]).second << endl;
}
}
}
return 0;
}
from bisect import bisect_left
N, Q = map(int, input().split())
# V[i] と対応する (i, S[i]) の列
merchandise = dict()
for i in range(N):
S, _V = input().split()
V = int(_V)
if not V in merchandise:
merchandise[V] = []
merchandise[V].append((i, S))
# V[i] を昇順に並べた列
prices = sorted(merchandise.keys())
for i in range(Q):
X = input()
# X = V[i] となる V[i] が存在すれば
if X in merchandise:
# S をすべて出力
print(' '.join(S for i, S in merchandise[V]))
else: # 存在しなければ
# X 以上のうち最小の V[i] を求めて
idx = bisect_left(prices, X)
# 大小関係をもとに場合分け
if idx == 0 or (idx < len(prices) and prices[idx - 1] + prices[idx] < 2 * X):
print(merchandise[prices[idx]][0][1])
elif idx == len(prices) or prices[idx - 1] + prices[idx] > 2 * X:
print(merchandise[prices[idx - 1]][0][1])
else: # 距離が等しければ番号が小さいほう
print(min(merchandise[prices[idx]][0], merchandise[prices[idx - 1]][0])[1])
posted:
last update:
