ABC344

基本情况

ABCE 秒了,D小细节处理出错(太久没写dp)+4。

A - Spoiler

https://atcoder.jp/contests/abc344/tasks/abc344_a

有更优雅的解法

signed main(){
	std::string s;
	std::cin >> s;
	std::cout << s.substr(0, s.find("|")) + s.substr(s.rfind("|") + 1) << '\n';
}

D - String Bags

https://atcoder.jp/contests/abc344/tasks/abc344_d

分组背包,但是字符串的细节要注意

signed main()
{
    std::cin.tie(nullptr)->sync_with_stdio(false);

    std::string s; std::cin >> s; int M = SZ(s);

    int N; std::cin >> N;

    const int MAX = std::numeric_limits<int>::max();
    std::vector<int> dp(M + 1, MAX); dp[0] = 0;

    int ans = MAX;

    for (int g = 1; g <= N; g++) {
        int A; std::cin >> A;
        auto ndp = dp;//这里是因为上一轮的被更新过的状态需要沿用到这一轮,否则下面直接min就不是最优
        for (int i = 0; i < A; i++) {
            std::string t; std::cin >> t;
            for (int j = 0; j + SZ(t) - 1 < M; j++) {
                if (s.substr(j, SZ(t)) == t and dp[j] != MAX) {
                    ndp[j + SZ(t)] = std::min(ndp[j + SZ(t)], dp[j] + 1);
                }
            }
        }
        dp = ndp;
    }

    if (dp[M] == MAX) {
        std::cout << -1 << '\n';
    } else {
        std::cout << dp[M] << '\n';
    }

    return 0;
}

E - Insert or Erase

https://atcoder.jp/contests/abc344/tasks/abc344_e

思路很直接,用 \(map\) 映射双链表的下标即可。

\(MyCode\)

signed main() {
    
    std::map<int, int> l, r;

    r[0] = INT_MAX;
    l[INT_MAX] = 0;

    int n, q;

    std::cin >> n;

    auto add = [&](int x, int y) -> void {//把y插入到x右边
        r[y] = r[x];
        l[r[x]] = y;
        r[x] = y;
        l[y] = x;
    };

    auto del = [&](int x) -> void {//删除x元素
        r[l[x]] = r[x];
        l[r[x]] = l[x];
    };  


    for (int i = 0, x = 0, y; i < n; i++) {//读入初始元素
        std::cin >> y;
        add(x, y);
        x = y;
    }

    std::cin >> q;

    for (int i = 0, op, x, y; i < q; i++) {
        std::cin >> op;
        if (op == 1) {
            std::cin >> x >> y;
            add(x, y);
        }
        else {
            std::cin >> x;
            del(x);
        }
    }   

    for (int x = r[0]; x != INT_MAX; x = r[x]) {
        std::cout << x << ' ';
    }
    
    return 0;
}

\(\texttt{STLcode}\)

signed main()
{
    std::cin.tie(nullptr)->sync_with_stdio(false);


    int N; std::cin >> N;
    std::vector<int> A(N); for (auto& x : A) {std::cin >> x;}
    std::list<int> L(A.begin(), A.end());
    std::map<int, std::list<int>::iterator> val_iter;
    for (auto it = L.begin(); it != L.end(); it++) {val_iter[*it] = it;}
    int Q; std::cin >> Q; while (Q--) {
        int opt; std::cin >> opt;
        if (opt == 1) {
            int x, y; std::cin >> x >> y;
            auto it = std::next(val_iter[x]);//因为insert是在左端插入
            val_iter[y] = L.insert(it, y);
        } else {
            int x; std::cin >> x; L.erase(val_iter[x]);
        }
    }

    for (auto& x : L) {std::cout << x << ' ';} std::cout << '\n';

    return 0;
}

F - Earn to Advance

https://atcoder.jp/contests/abc344/tasks/abc344_f

贪心简化DP

可以将“通过 \(P_{i,j}\) 增加金钱”的操作替换为“通过迄今为止经过的所有格子中的最大 \(P_{i,j}\) 来增加金钱”,而不改变答案。

因此,可以假设只有在需要时才赚钱;这样一来,一旦确定了一条路径,最优过程也就唯一确定了。

特别地,我们只需记住“迄今为止经过的所有格子中的最大 \(P_{i,j}\)”,因此可以设计这个状态:

\[dp_{i, j, x, y}表示从 (1, 1) 到 (i, j), 其中最大的 P 为 P_{x, y} 的情况下的最小步数(单指停留步)和最小花费。 \]

signed main()
{
    std::cin.tie(nullptr)->sync_with_stdio(false);

    int N; std::cin >> N;
    std::vector P(N, std::vector<int>(N)), R(N, std::vector<int>(N - 1)), D(N - 1, std::vector<int>(N));;
    auto read = [&](auto& V) {for (auto& vec : V) for (auto& x : vec) {std::cin >> x;};}; read(P); read(R); read(D);

    //dp[i][j][x][y] 表示从 (1, 1) 到 (i, j), 其中最大的 P 为 P(x, y) 的情况下的最小步数(单指停留步)和最小花费。
    std::vector dp(N, std::vector(N, std::vector(N, std::vector(N, std::make_pair(inf, inf)))));
    dp[0][0][0][0] = {0, 0};

    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) for (int x = 0; x <= i; x++) for (int y = 0; y <= j; y++) {
        if (j + 1 < N) {//向右走
            auto res = dp[i][j][x][y]; auto&[step, cost] = res;
            cost += R[i][j];
            if (cost > 0) {
                i64 add_step = (cost - 1) / P[x][y] + 1;//向下取整后再加一,算出到达当前这个花费,至少要停多少步
                step += add_step; cost -= add_step * P[x][y];//增加步数,减去花费
            }
            dp[i][j + 1][x][y] = std::min(dp[i][j + 1][x][y], res); dp[i][j + 1][i][j + 1] = std::min(dp[i][j + 1][i][j + 1], res); 
        }
        if (i + 1 < N) {
            auto res = dp[i][j][x][y]; auto&[step, cost] = res;
            cost += D[i][j];
            if (cost > 0) {
                i64 add_step = (cost - 1) / P[x][y] + 1;
                step += add_step; cost -= add_step * P[x][y];
            }
            dp[i + 1][j][x][y] = std::min(dp[i + 1][j][x][y], res); dp[i + 1][j][i + 1][j] = std::min(dp[i + 1][j][i + 1][j], res);
        }
    }

    std::cout << dp[N - 1][N - 1][N - 1][N - 1].first + 2 * (N - 1) << '\n';//停留的花费,加上(1, 1)到(n, n)的曼哈顿距离

    return 0;
}
posted @ 2024-03-09 22:57  加固文明幻景  阅读(45)  评论(0编辑  收藏  举报