Skip to content

第 357 场周赛

比赛链接

Date: 2023-08-06

A 故障键盘

class Solution {
public:
    string finalString(string s) {
        string t = "";
        for (auto c : s) {
            if (c == 'i') {
                reverse(t.begin(), t.end());
            } else {
                t += c;
            }
        }
        return t;
    }
};

复杂度分析

  • 时间复杂度:\(O(n)\)
  • 空间复杂度:\(O(1)\)

B 判断是否能拆分数组

比赛时,使用了 DP,记 \(d[i][j]\) 表示区间 \((i, j)\) 能否拆分。

但其实只需要有任意一组连续两个数字之和大于等于 \(m\) 即可。

class Solution {
public:
    bool canSplitArray(vector<int>& nums, int m) {
        int n = nums.size();
        vector<int> sum(n + 1);
        vector<vector<int>> d(n, vector<int>(n, 0));
        for (int i = 0; i < n; i++) {
            sum[i + 1] = sum[i] + nums[i];
            d[i][i] = 1;
        }
        for (int len = 2; len <= n; len++) {
            for (int l = 0; l + len - 1 < n; l++) {
                int r = l + len - 1;
                for (int k = l; k < r; k++) {
                    d[l][r] = d[l][r] || (d[l][k] && d[k + 1][r] && (l == k || sum[k + 1] - sum[l] >= m) && (k + 1 == r || sum[r + 1] - sum[k + 1] >= m));
                }
            }
        }
        return d[0][n - 1];
    }
};

复杂度分析

  • 时间复杂度:\(O(n^3)\)
  • 空间复杂度:\(O(1)\)

C 找出最安全路径

很无脑的题,码量有点大。

class Solution {
public:
    static constexpr int dir[4][2] = {
        {0, 1}, {0, -1}, {1, 0}, {-1, 0}
    };
    int maximumSafenessFactor(vector<vector<int>>& g) {
        int n = g.size(), m = g[0].size();
        queue<pair<int, int>> q;
        vector<vector<int>> v(n, vector<int>(n, -1));
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (g[i][j] == 1) {
                    v[i][j] = 0;
                    q.push({i, j});
                }
            }
        }
        while (q.size()) {
            auto [x, y] = q.front(); q.pop();
            for (int i = 0; i < 4; i++) {
                int nx = x + dir[i][0];
                int ny = y + dir[i][1];
                if (nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
                if (v[nx][ny] == -1) {
                    v[nx][ny] = v[x][y] + 1;
                    q.push({nx, ny});
                }
            }
        }

        auto check = [&](int mid) {
            queue<pair<int, int>> q;
            if (v[0][0] < mid) return false;
            q.push({0, 0});
            vector<vector<int>> vis(n, vector<int>(n, 0));
            while (q.size()) {
                auto [x, y] = q.front(); q.pop();
                if (x == n - 1 && y == n - 1) {
                    return true;
                }
                for (int i = 0; i < 4; i++) {
                    int nx = x + dir[i][0];
                    int ny = y + dir[i][1];
                    if (nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
                    if (v[nx][ny] >= mid && vis[nx][ny] == 0) {
                        q.push({nx, ny});
                        vis[nx][ny] = 1;
                    }
                }
            }
            return false;
        };

        int l = 0, r = n * m;
        while (l < r) {
            int mid = l + r + 1 >> 1;
            if (check(mid)) {
                l = mid;
            } else {
                r = mid - 1;
            }
        }
        return l;
    }
};

复杂度分析

  • 时间复杂度:\(O(n^2\log n^2)\)
  • 空间复杂度:\(O(n^2)\)

D 子序列最大优雅度

我们先忽略种类数,只考虑 profit。那么我们会选择前 \(k\) 大的 item,种类数为 \(c\)

我们会让种类数变得更少吗?并不,减少种类数必然会引入更低的 profit,并不能使答案更优。

那么如何让种类数变多?已选择的种类并不会被删除,只需要新增种类。新增种类的同时,需要去除旧种类中 profit 最低的(并且该种类个数必须大于 1)。

class Solution {
public:
    using ll = long long;
    long long findMaximumElegance(vector<vector<int>>& items, int k) {
        int n = items.size();
        sort(items.begin(), items.end(), [&](vector<int>& lth, vector<int>& rth) {
            return lth[0] > rth[0];
        });
        vector<int> c(n);
        ll kind = 0;
        ll sum = 0;
        priority_queue<int, vector<int>, greater<int>> q;
        for (int i = 0; i < k; i++) {
            sum += items[i][0];
            c[items[i][1] - 1]++;
            if (c[items[i][1] - 1] == 1) {
                kind++;
            } else {
                q.push(items[i][0]);
            }
        }
        ll res = sum + kind * kind;
        for (int i = k; i < n; i++) {
            if (c[items[i][1] - 1] != 0 || q.size() == 0) {
                continue;
            }
            c[items[i][1] - 1]++;
            kind++;
            sum -= q.top(); q.pop();
            sum += items[i][0];
            res = max(res, sum + kind * kind);
        }
        return res;
    }
};

复杂度分析

  • 时间复杂度:\(O(n\log n)\)
  • 空间复杂度:\(O(n)\)
本文访问