CF45E - Director(構造性演算法 + 字串 + 貪心 / *2000)
45E - Director(源地址自⇔CF45E)
目錄tag
⇔構造性演算法、⇔字串、⇔貪心、⇔*2000
題意
給定 \(N\) 個姓和 \(N\) 個名,要求兩兩組合所有的姓和名,使得姓和名開頭字母相同的對數最多,且全部姓名的總字典序儘可能的小。
思路
賽時思路(是錯的)
點選檢視原因
其實這道題的題意非常難懂,在初見的時候以為這是一道打卡水題,所以想的很簡單,以為只需要按照字典序進行一遍排序即可。結果錯誤了兩次之後發現並不是如此(然而不信邪的隊友便又多交了兩發WA......),題目中最關鍵的那一行條件其實在初見的時候沒有讀出來,原文如下:
First of all Vasya wants to maximize the number of the pairs, in which the name and the surname start from one letter.
需要先將所有首字母相同的姓和名配對,然後再思考字典序的問題。
可是,這道題的難點還不止於此,思考以下樣例:
姓:Sa Ss Aa,名:Sc Sd Sz
如果不考慮字典序,只顧首字母匹配的話,顯然,答案為 \(\tt{}Sa\ Sc,\ Ss\ Sd\) 和 \(\tt{}Aa\ Sz\) ,然而,為了讓總字典序最小,最佳的匹配應當為 \(\tt{}Sa\ Sd,\ Ss\ Sz\)
正解(自己做法)
我們按字典序逆序 ( \(\tt{}Z - A\) )考慮本題。
-
假如 \(\tt{}name\) 的數量多於 \(\tt{}surname\) ,並且待匹配陣列 \(S\) 中有內容,那麼優先將多餘的 \(\tt{}name\) 和 \(S\) 匹配(注意, \(\tt{}name\) 中字典序升序,直接從尾部取即可,而 \(S\) 中字典序降序,需要從頭部取);
-
假如 \(\tt{}surname\) 的數量多於 \(\tt{}name\) ,並且待匹配陣列 \(N\) 中有內容,那麼優先將多餘的 \(N\) 和 \(\tt{}surname\)
-
完成前兩輪操作後,若仍有 \(\tt{}name\) 和 \(\tt{}surname\) 可匹配,依次配對並放入答案陣列 \(Ans\) ;
-
假如匹配完成後仍有多餘的未匹配項,則直接放入對應的待匹配陣列 \(N\) 和 \(S\) 。
最後,排序 \(Ans\) 陣列並輸出即可。
AC程式碼
點選檢視程式碼
//====================
#define int LL
const int N = 1e6 + 7;
vector<string> name[N], surname[N], ans, _N, _S;
//====================
void Solve() {
int n; cin >> n;
for (int i = 1; i <= n; ++ i) {
string s; cin >> s;
name[s[0] - 'A'].push_back(s);
}
for (int i = 1; i <= n; ++ i) {
string s; cin >> s;
surname[s[0] - 'A'].push_back(s);
}
for (int i = 25; i >= 0; -- i) {
auto x = name[i], y = surname[i];
sort(x.begin(), x.end()), sort(y.begin(), y.end());
while (_N.size() != 0 && x.size() < y.size()) {
reverse(_N.begin(), _N.end());
ans.push_back(_N.back() + " " + y.back());
_N.pop_back(), y.pop_back();
reverse(_N.begin(), _N.end());
}
while (_S.size() != 0 && x.size() > y.size()) {
reverse(_S.begin(), _S.end());
ans.push_back(x.back() + " " + _S.back());
_S.pop_back(), x.pop_back();
reverse(_S.begin(), _S.end());
}
while (x.size() != 0 && y.size() != 0) {
ans.push_back(x.back() + " " + y.back());
x.pop_back(), y.pop_back();
}
while (x.size() != 0) {
_N.push_back(x.back());
x.pop_back();
}
while (y.size() != 0) {
_S.push_back(y.back());
y.pop_back();
}
}
sort(ans.begin(), ans.end());
for (int i = 0; i < n - 1; ++ i) cout << ans[i] << ", ";
cout << ans.back();
}
錯誤次數
(賽時 1 次)理解錯題意。
(賽後 1 次)也是理解錯了題意。
文 / WIDA
2022.03.25 成文
首發於WIDA個人部落格,僅供學習討論