KMIN
2017-08-04Content:
1. Bài gốc
2. Đề bài
Cho 2 dãy số nguyên A và B có M và N phần tử. Với mọi số A[i] thuộc A và B[j] thuộc B người ta tính tổng nó. Tất cả các tổng này sau khi được sắp xếp không giảm sẽ tạo thành dãy C.
Nhiệm vụ của bạn là: Cho 2 dãy A, B. Tìm K số đầu tiên trong dãy C.
Giới hạn:
- 1 ≤ M, N, K ≤ 50000
- 1 ≤ Ai, Bi ≤ 109
Định dạng test
Input:
- Dòng đầu tiên gồm 3 số: M, N, K.
- M dòng tiếp theo gồm M số mô tả dãy A.
- N dòng tiếp theo gồm N số mô tả dãy B.
Output:
- Gồm K dòng tương ứng là K phần tử đầu tiên trong dãy C.
Ví dụ:
3. Thuật toán
Giả sử đã chọn được a[i] + b[j]
là phần tử để đưa vào K số, để tìm phần tử “tiềm năng” tiếp theo, có hai trường hợp:
a[k] + b[j]
, vớia[k]
là phẩn tử nhỏ nhất và lớn hơn hoặc bằnga[i]
trong dãy A.a[i] + b[k]
, vớib[k]
là phần tử nhỏ nhất và lớn hơn hoặc bằngb[j]
trong dãy B.
Giả sử chọn cách tiếp cận thứ nhất, để tối ưu thuật toán ta sử dụng 2 kĩ thuật sau:
- Sắp xếp mảng a không giảm: giả sử đã chọn
a[i] + b[j]
, thì ứng viên “tiềm năng” tiếp theo sẽ làa[i+1] + b[j]
. - Sử dụng cấu trúc heap để chọn ra phần tử nhỏ nhất trong những
a[i] + b[j]
“tiềm năng” (và cả vị tríi
,j
của nó).
4. Source code
Ngôn ngữ: C++.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
typedef pair<ll, ii> lii;
const int N = 5e4 + 5;
int m, n, k;
ll a[N], b[N];
vector<ll> res;
priority_queue<lii, vector<lii>, greater<lii> > Q;
int main() {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
// input
cin >> m >> n >> k;
FOR(i,1,m) cin >> a[i];
FOR(i,1,n) cin >> b[i];
// preprocessing
sort(a+1, a+m+1);
FOR(i,1,n) Q.push(mp(a[1] + b[i], mp(1, i)));
// solve
while(k--) {
lii p = Q.top();
res.pb(p.fi);
int i = p.se.fi;
int j = p.se.se;
// update
Q.pop();
if (i+1 <= m)
Q.push(mp(a[i+1] + b[j], mp(i+1, j)));
}
// output
REP(i,sz(res)) {
cout << res[i];
if (i+1 < sz(res)) cout << '\n';
}
return 0;
}
5. Độ phức tạp
O(max(M, n) * logN)