AcWing 第 3 場周賽
阿新 • • 發佈:2021-07-05
比賽連結:Here
AcWing 3660. 最短時間
比較四個方向和 \((r,c)\) 的距離
void solve() {
ll n, m, r, c;
cin >> n >> m >> r >> c;
cout << max(max(r + c - 2, r + m - 1 - c), max(n + c - r - 1, n + m - r - c)) << "\n";
}
AcWing 3661. 重置數列
列舉相同值即可
void solve() { int n, k; cin >> n >> k; bool f[110] = {false}; vector<int>a(n + 1); for (int i = 1; i <= n; ++i)cin >> a[i], f[a[i]] = true; int cnt = n; for (int i = 1; i <= 100; ++i) { if (f[i]) { int t = 0; for (int j = 1; j <= n; ++j) { if (a[j] == i)continue; else t++, j = j + k - 1; } cnt = min(cnt, t); } } cout << cnt << "\n"; }
AcWing 3662. 最大上升子序列和
(離散化,樹狀陣列) \(O(nlogn)\)
眾所周知,與求上升子序列相關的優化一般有兩種:
- 單調棧 & 二分優化
- 線段樹 | 樹狀陣列 | 平衡樹等資料結構優化
這裡求的是上升子序列中所有元素的和的最大值,不太好用單調棧+二分,故想到用樹狀陣列。
可能有些人對資料結構優化最長上升子序列不太瞭解,這裡說一下思路。
先考慮暴力DP:設 \(f[i]\) 表示在 \(a_1∼a_i\) 中,且以 \(a_i\) 結尾的所有上升子序列中,元素和的最大值。
轉移方程:
\[f[i] = a_i + max_{0\le j<i,a_j<a_i}f[j] \]將序列 \(a\)
設 \(g_x\) 表示所有 \(j < i\) 且 \(a_j = x\) 的 \(f_j\) 的最大值,那麼 \(max_{0\le j<i,a_j<a_i}f[j]\) 就等於 \(max_{x <a_i}g_x\) ,注意到這項是 \(g\) 的一個字首最大值,這恰可以用樹狀陣列動態維護。
具體可見程式碼。
時間複雜度:
離散化 \(O(nlogn)\),樹狀陣列 \(O(nlogn)\),故總複雜度為 \(O(nlogn)\)。
using ll = long long; const int N = 1e5 + 10, mod = 1e9 + 7; int n, a[N], diff[N], sz; // 離散化 // 樹狀陣列 ll f[N], res; inline void add(int x, const ll val) {for (; x <= sz; x += x & -x) f[x] = max(f[x], val);} inline ll query(int x) { ll res = 0; for (; x; x &= x - 1)res = max(res, f[x]); return res; } void solve() { cin >> n; for (int i = 1; i <= n; ++i) cin >> a[i], diff[i - 1] = a[i]; sort(diff, diff + n); sz = unique(diff, diff + n) - diff; for (int i = 1; i <= n; ++i) { a[i] = lower_bound(diff, diff + sz, a[i]) - diff + 1; ll t = diff[a[i] - 1] + query(a[i] - 1); res = max(res, t), add(a[i], t); } cout << res << "\n"; }
The desire of his soul is the prophecy of his fate
你靈魂的慾望,是你命運的先知。