Hướng dẫn cho Ổ cắm
Chỉ sử dụng khi thực sự cần thiết như một cách tôn trọng tác giả và người viết hướng dẫn này.
Chép code từ bài hướng dẫn để nộp bài là hành vi có thể dẫn đến khóa tài khoản.
Chép code từ bài hướng dẫn để nộp bài là hành vi có thể dẫn đến khóa tài khoản.
Authors:
\(\color{red}{\text{Spoiler Alert}_{{}_{{}^{{}^{v2.0}}}}}\)
\(\color{red}{\text{Khuyến khích bạn đọc trước khi đọc phần lời giải xin hãy thử code ra thuật của mình dù nó có sai hay đúng}}\)
\(\color{red}{\text{Sau đó từ phần bài giải và thuật toán trước đó mà đối chiếu, rút nhận xét với thuật của mình và thu được bài học (không lãng phí thời gian đâu).}}\)
\(\color{orange}{\text{Hint 1 <Brute-force>}}\)
- Thử từng dãy và kiểm tra trong những cái hợp lệ lấy cái nhỏ nhất
\(\color{orange}{\text{Hint 2 <Greedy> <Sorting>}}\)
- Ưu tiên lấy những cái lớn hơn chúng ta sẽ lấy ít cái nhất
\(\color{orange}{\text{Hint 3 <Distrubition Counting>}}\)
- Vì giới hạn \(a_i\) (\(1 \leq a_i \leq 50\)) nhỏ hơn nhiều với \(n\)
Chúng ta có thể lưu các giá trị theo tần số xuất hiện và duyệt từ giá trị lớn tới bé
\(\color{goldenrod}{\text{Approach}}\)
-
Đầu tiên chúng ta có miễn phí một ô ở đầu nên ta sẽ giảm \(m\) đi 1
-
Với những ổ cắm sau, mỗi ổ cắm tốn 1 ô để cắm sang ổ khác, nên ổ có \(x\) ô cắm sẽ có \(x - 1\) ô cho các thiết bị
Ổ cắm \(1\) là vô nghĩa nên ta cũng chẳng cần xét
\(\color{green}{\text{Preference AC Code }}\): Greedy, Distrubition Counting
\(^{^{\color{purple}{\text{Complexity : }} O(n)\ \color{purple}{\text{time}}\ ||\ O(1)\ \color{purple}{\text{memory}}}}\)
C++
int main()
{
int n, k;
cin >> n >> k;
k--; /// free
/// distrubition counting
vector<int> a(51, 0);
while (n--) a[readInt()]++;
int res = 0;
for (int x = 50; x >= 2; --x)
{
while (a[x] > 0)
{
int t = min((k + (x - 1) - 1) / (x - 1), a[x]);
k -= (x - 1) * t;
a[x] -= t;
res += t;
if (k <= 0)
{
cout << res;
return 0;
}
}
}
cout << -1;
return 0;
}
Bình luận
distribution hay là distrubition vậy ạ :vv