AtCoder Beginner Contest 344

A - Spoiler

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = int64_t;
using ldb = long double;

#define int i64
using vi = vector<int>;
using pii = pair<int, int>;

const int mod = 998244353;
const int inf = INT_MAX;

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    string s;
    cin >> s;
    int f = 1;
    for( auto i : s ){
        if( i == '|' ) f ^= 1;
        if( f and i != '|') cout << i;
    }
    return 0;
}

B - Delimiter

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = int64_t;
using ldb = long double;

#define int i64
using vi = vector<int>;
using pii = pair<int, int>;

const int mod = 998244353;
const int inf = INT_MAX;

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    vi a;
    int x;
    while( cin >> x ) a.push_back(x);
    reverse(a.begin(), a.end());
    for( auto i : a )
        cout << i << "\n";
    return 0;
}

C - A+B+C

先离线处理出所有可能组合出的数字。

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = int64_t;
using ldb = long double;

#define int i64
using vi = vector<int>;
using pii = pair<int, int>;

const int mod = 998244353;
const int inf = INT_MAX;

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n;
    cin >> n;
    vi a(n);
    for (auto &i: a) cin >> i;
    int m;
    cin >> m;
    vi b(m);
    for (auto &i: b) cin >> i;
    int l;
    cin >> l;
    vi c(l);
    for (auto &i: c) cin >> i;
    set<int> vis;
    for (auto i: a)
        for (auto j: b)
            for (auto k: c)
                vis.insert(i + j + k);
    int q;
    cin >> q;
    for( int x ; q ; q -- ){
        cin >> x;
        if( vis.count(x) ) cout << "Yes\n";
        else cout << "No\n";
    }
    return 0;
}

D - String Bags

其实是一个简单的01背包问题。

\(f[i][j]\)表示前\(i\)个串拼出长度为\(j\)的前缀的最小花费。

现在对于一个给定的串,我们枚举他放置的位置,先看这个位置之前能不能被拼出来,再看能不能放进这个位置即可。

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = int64_t;
using ldb = long double;

#define int i64
using vi = vector<int>;
using pii = pair<int, int>;

const int mod = 998244353;
const int inf = INT_MAX;

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    string t;
    cin >> t;
    int m = t.size();
    int n;
    cin >> n;
    string s;
    vector<int> f(m + 1, inf);
    f[0] = 0;
    for (int x; n; n--) {
        cin >> x;
        auto g = f;
        for (int len; x; x--) {
            cin >> s, len = s.size();
            for (int p = 0; p + len <= m; p++) {
                if (f[p] == inf) continue;
                if (t.substr(p, s.size()) == s)
                    g[p + len] = min(g[p + len], f[p] + 1);
            }
        }
        f.swap(g);
    }
    if (f.back() == inf) cout << "-1\n";
    else cout << f.back() << "\n";
    return 0;
}

还在群里学到了一个用map的写法

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;
using ldb = long double;

#define int i64

using vi = vector<int>;
using pii = pair<int, int>;

const int inf = 1e9;


i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    string T;
    cin >> T;
    map<string, int> f;
    f[""] = 0;
    for (string s = ""; auto i: T)
        s += i, f[s] = inf;

    int n;
    cin >> n;
    for (int x; n; n--) {
        cin >> x;
        auto g = f;
        for (string s, ns; x; x--) {
            cin >> s;
            for (auto [k, v]: f) {
                ns = k + s;
                if (v == inf or ns.size() > T.size() or g.count(ns) == 0) 
                    continue;
                g[ns] = min(g[ns], v + 1);
            }
        }
        f.swap(g);
    }
    if (f[T] == inf) f[T] = -1;
    cout << f[T] << "\n";
    return 0;
}

E - Insert or Erase

单说插入和删除操作实际上都可以用链表\(O(1)\)的实现,难点是如何快速找到要插入或修改的位置。

我这里使用std::map<int,std::pair<int,int>>来模拟了链表的执行过程。

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = int64_t;
using ldb = long double;

#define int i64
using vi = vector<int>;
using pii = pair<int, int>;

const int mod = 998244353;
const int inf = INT_MAX;

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n;
    cin >> n;
    map<int, pii> List;
    for (int i = 1, x, lst = 0; i <= n; i++) {
        cin >> x;
        List[lst].second = x;
        List[x] = pair(lst, inf);
        lst = x;
    }
    int q;
    cin >> q;
    for (int op, lst, nxt, x; q; q--) {
        cin >> op;
        if (op == 1) {
            cin >> lst >> x;
            nxt = List[lst].second;
            List[x] = pair(lst, nxt);
            List[lst].second = List[nxt].first = x;
        } else {
            cin >> x;
            tie(lst, nxt) = List[x];
            List[x] = pair(-1, -1);
            List[lst].second = nxt;
            List[nxt].first = lst;
        }
    }
    for (int i = List[0].second; i != inf; i = List[i].second)
        cout << i << " ";
    cout << "\n";
    return 0;
}

F - Earn to Advance

一个比较板的dp。据说和某年的csp-j t2比较类似。

设 dp的状态为$f[i][j][x][y] \(表示走到\)(i,j)\(点且路径中经过\)p\(的最大值在\)(x,y)\(上,这样实际上就是\)O(n^4)\(的枚举就行。要注意的就是向下一步走的时候要判断\)p$最大值位置是否发生变化。

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;
using ldb = long double;

#define int i64
using vi = vector<int>;
using pii = pair<int, int>;

const int inf = LLONG_MAX;


i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n;
    cin >> n;

    vector p(n, vi(n));
    for (auto &it: p)
        for (auto &i: it) cin >> i;

    vector r(n, vi(n - 1));
    for (auto &it: r)
        for (auto &i: it) cin >> i;

    vector d(n - 1, vi(n));
    for (auto &it: d)
        for (auto &i: it) cin >> i;

    vector f(n, vector(n, vector(n, vector(n, pair(inf, -inf)))));
    f[0][0][0][0] = pair(0, 0);

    auto calc = [](int a, int b, int c) {
        if (a >= b) return 0ll;
        return (b - a + c - 1) / c;
    };

    auto cmp = [](pii x, pii y) {
        if (x.first != y.first) return x.first < y.first;
        return x.second > y.second;
    };
    for (int i = 0, wait, newX, newY, newDis, newLst; i < n; i++)
        for (int j = 0; j < n; j++)
            for (int x = 0; x <= i; x++)
                for (int y = 0; y <= j; y++) {
                    const auto &[dis, lst] = f[i][j][x][y];
                    if (dis == inf) continue;
                    if (i + 1 < n) {
                        wait = calc(lst, d[i][j], p[x][y]);
                        newX = x, newY = y;
                        if (p[i + 1][j] > p[x][y]) newX = i + 1, newY = j;
                        newDis = dis + wait + 1, newLst = lst + wait * p[x][y] - d[i][j];
                        f[i + 1][j][newX][newY] = min(f[i + 1][j][newX][newY], pair(newDis, newLst),cmp);
                    }
                    if (j + 1 < n) {
                        wait = calc(lst, r[i][j], p[x][y]);
                        newX = x, newY = y;
                        if (p[i][j + 1] > p[x][y]) newX = i, newY = j + 1;
                        newDis = dis + wait + 1, newLst = lst + wait * p[x][y] - r[i][j];
                        f[i][j + 1][newX][newY] = min(f[i][j + 1][newX][newY], pair(newDis, newLst), cmp);
                    }
                }
    int res = inf;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            res = min(res, f[n - 1][n - 1][i][j].first);
    cout << res << "\n";
    return 0;
}
posted @ 2024-03-10 15:22  PHarr  阅读(30)  评论(0编辑  收藏  举报