# 2022年6月APCS題解 ## [1. 數字遊戲](https://zerojudge.tw/ShowProblem?problemid=i399) 去除重複元素然後排序,因為我很懶所以用`set<int, greater<int> >`。 :::spoiler code: ```cpp= #include <iostream> #include <set> using namespace std; int main() { cin.tie(nullptr)->sync_with_stdio(false); set<int, greater<int> > st; for (int x, i = 0; i < 3; i++) { cin >> x; st.insert(x); } cout << 4 - st.size() << ' '; int j = 0; for (const auto& i : st) { cout << i << " \n"[(++j) == st.size()]; } return 0; } ``` ::: ## [2. 字串解碼](https://zerojudge.tw/ShowProblem?problemid=i400) 題目是要解碼,所以要反過來做。 :::spoiler code: ```cpp= #include <bits/stdc++.h> using namespace std; int main() { cin.tie(nullptr)->sync_with_stdio(false); int m, n; cin >> m >> n; vector<string> v(m); for (string& s : v) cin >> s; string s; cin >> s; reverse(v.begin(), v.end()); vector<string> tmp(2); int cnt = 0; for (const string& ss : v) { tmp[0].clear(), tmp[0].reserve(n); tmp[1].clear(), tmp[1].reserve(n); cnt = 0; for (int i = n - 1; i >= 0; i--) { if (ss[i] == 49) cnt ^= 1; tmp[ss[i] ^ 48].push_back(s[i]); } reverse(tmp[0].begin(), tmp[0].end()); s = tmp[0] + tmp[1]; if (cnt) { for (int i = 0, j = n - (n >> 1); j < n; i++, j++) { swap(s[i], s[j]); } } } cout << s << '\n'; return 0; } ``` ::: ## [3. 雷射測試](https://zerojudge.tw/ShowProblem?problemid=i401) 我用`map`套`set`來存鏡子的位置和方向,`stx`是拿`x`座標去對`y`座標,`sty`同理,之所以用`set`是因為需要找最近的鏡子四個方向分開處理,然後`map`是我懶得離散化,也能改成`unordered_map`,不過時間差異不大,都能過,複雜度$O(n{\log}n)$。 :::spoiler code: ```cpp= #include <bits/stdc++.h> #define F first #define S second using namespace std; using i64 = long long; template <class T> using P = pair<T, T>; enum dir { L, R, U, D }; int main() { cin.tie(nullptr)->sync_with_stdio(false); unordered_map<int, set<P<int> > > stx, sty; int n, ans = 0; cin >> n; for (int x, y, t; n--; ) { cin >> x >> y >> t; stx[x].insert(P<int>(y, t)); sty[y].insert(P<int>(x, t)); } dir _d = R; set<P<int> >::iterator it; for (int x = 0, y = 0, flag = 1; flag; ) { switch(_d) { case L: it = sty[y].lower_bound(P<int>(x, 0)); if (it == sty[y].begin()) { flag ^= 1; } else { --it; if (it->S) { _d = U; } else { _d = D; } x = it->F; ++ans; } break; case R: it = sty[y].upper_bound(P<int>(x, 1)); if (it == sty[y].end()) { flag ^= 1; } else { if (it->S) { _d = D; } else { _d = U; } x = it->F; ++ans; } break; case U: it = stx[x].upper_bound(P<int>(y, 1)); if (it == stx[x].end()) { flag ^= 1; } else { if (it->S) { _d = L; } else { _d = R; } y = it->F; ++ans; } break; case D: it = stx[x].lower_bound(P<int>(y, 0)); if (it == stx[x].begin()) { flag ^= 1; } else { --it; if (it->S) { _d = R; } else { _d = L; } y = it->F; ++ans; } break; } } cout << ans << '\n'; return 0; } ``` ::: ## [4. 內積](https://zerojudge.tw/ShowProblem?problemid=i402) 這題很明顯是個DP,於是可以定義`dp[i][j]`為取$a_i$和$b_j$當結尾的內積最大值,注意到`dp[i][j]`只有可能從`dp[i-1][j-1]`轉移,所以這題其實是斜向的連續最大和,超酷。為了實作方便,設定上面DP陣列的`i`和`j`是`1-based`,然後DP初始化為`0`,每次更新DP陣列就對`ans`取一次`max`。 然後記得要把一個向量`reverse`之後再算一次。 複雜度:$O(nm)$。 :::spoiler code: ```cpp= #include <bits/stdc++.h> using namespace std; int main() { cin.tie(nullptr)->sync_with_stdio(false); int n, m, ans = INT_MIN; cin >> n >> m; vector<vector<int> > dp(n + 1, vector<int>(m + 1, 0)); vector<int> a(n), b(m); for (int& i : a) cin >> i; for (int& i : b) cin >> i; for (int i = 1, t; i <= n; i++) { for (int j = 1; j <= m; j++) { dp[i][j] = max(dp[i - 1][j - 1] + (a[i - 1] * b[j - 1]), (a[i - 1] * b[j - 1])); ans = max(ans, dp[i][j]); } } for (vector<int>& v : dp) { fill(v.begin(), v.end(), 0); } reverse(a.begin(), a.end()); for (int i = 1, t; i <= n; i++) { for (int j = 1; j <= m; j++) { dp[i][j] = max(dp[i - 1][j - 1] + (a[i - 1] * b[j - 1]), (a[i - 1] * b[j - 1])); ans = max(ans, dp[i][j]); } } cout << ans << '\n'; return 0; } ``` :::