Codeforces 1611G 贪心 + 二分 / Dilworth 定理 + DP

题意

传送门 Codeforces 1611G Robot and Candies

题解

对于节点 ( i , j ) (i,j) (i,j) ,每一步后 i + j i+j i+j 奇偶性不变,故可以根据奇偶性分别求解。

贪心 + 二分

依次扫描 i + j = c i + j = c i+j=c,维护一个已使用的 Robot 集合,对于任一个有物品的节点 ( i , j ) (i, j) (i,j),二分求解恰好能走到此节点的 Robot,安排其走到 ( i , j ) (i, j) (i,j);反之,新增 Robot。

#include 
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int tt;
    cin >> tt;
    while (tt--) {
        int n, m;
        cin >> n >> m;
        vector<string> ss(n);
        for (int i = 0; i < n; ++i) {
            cin >> ss[i];
        }

        vector<vector<int>> pos(n + m - 1);
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                if (ss[i][j] == '1') {
                    pos[i + j].push_back(i);
                }
            }
        }

        int res = 0;
        for (int bg = 0; bg < 2; ++bg) {
            vector<int> a;
            for (int k = bg, add = 0; k < n + m - 1; k += 2, add += 1) {
                for (int i = (int)pos[k].size() - 1; i >= 0;) {
                    int x = pos[k][i];
                    int j = lower_bound(a.begin(), a.end(), x - add, greater<int>()) - a.begin();
                    if (j == (int)a.size()) {
                        res += 1;
                        a.push_back(x - add);
                        break;
                    }
                    while (i >= 0 && pos[k][i] - add >= a[j]) {
                        i -= 1;
                    }
                    a[j] = x - add;
                }
            }
        }

        cout << res << '\n';
    }

    return 0;
}
Dilworth 定理 + DP

根据 Dilworth 定理,最小链划分等于最长反链。那么类似于 P3974 [TJOI2015]组合数学,DP 求解最长反链即可。此处反链上任一对节点 ( u , v ) (u,v) (u,v) 满足, ∣ x u − x v ∣ < ∣ y u − y v ∣ \lvert x_u - x_v\rvert < \lvert y_u - y_v\rvert xuxv<yuyv

#include 
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int tt;
    cin >> tt;
    while (tt--) {
        int n, m;
        cin >> n >> m;
        vector<string> ss(n);
        for (int i = 0; i < n; ++i) {
            cin >> ss[i];
        }
        vector<vector<int>> dp(n, vector<int>(m));
        vector<int> res(2);
        for (int j = 0; j < m; ++j) {
            for (int i = 0; i < n; ++i) {
                int pre = 0;
                if (j - 2 >= 0) {
                    pre = dp[i][j - 2];
                }
                dp[i][j] = pre + (ss[i][j] == '1');
                if (j - 1 >= 0) {
                    if (i - 1 >= 0) {
                        dp[i][j] = max(dp[i][j], dp[i - 1][j - 1]);
                    }
                    if (i + 1 < n) {
                        dp[i][j] = max(dp[i][j], dp[i + 1][j - 1]);
                    }
                }

                res[(i + j) & 1] = max(res[(i + j) & 1], dp[i][j]);
            }
        }

        cout << res[0] + res[1] << '\n';
    }

    return 0;
}

你可能感兴趣的:(数学,基本算法,算法)