zoukankan      html  css  js  c++  java
  • Codeforces Round #709 (Div. 2, based on Technocup 2021 Final Round)

    Codeforces Round #709 (Div. 2, based on Technocup 2021 Final Round)

    A - Prison Break

    int main() {
        IOS;
        for (cin >> _; _; --_) {
            ll n, m; cin >> n >> m;
            cout << (m - 1) * n + n << '
    ';
        }
        return 0;
    }
    

    B - Restore Modulo

    (a_i - a_{i - 1}) 注意到只有两种结果

    1. (a_i - a_{i - 1} < 0) 其值为 (c - m)
    2. (a_i - a_{i - 1} geqslant 0) 其值为 (c)

    (a_i - a_{i - 1}) 值大于2个无解, 有两个值且不是一个大于等于0 小于0 无解

    (a_i - a_{i - 1}) 值有一个, m无限大

    剩下的直接算出来(c, m) 再去特判 (m leqslant a_i) 即可

    ll a[N];
     
    int main() {
        IOS;
        for (cin >> _; _; --_) {
            cin >> n >> a[1]; set<ll> st; ll m, c;
            rep(i, 2, n) cin >> a[i], st.insert(a[i] - a[i - 1]);
            if (st.size() > 2) { cout << "-1
    "; continue; }
            else if (st.size() == 2 && *st.rbegin() < 0) { cout << "-1
    "; continue; }
            else if (st.size() == 2 && *st.begin() >= 0) { cout << "-1
    "; continue; }
            else if (st.size() == 2) m = *st.rbegin() - *st.begin(), c = *st.rbegin();
            else if (st.size() <= 1) { cout << "0
    "; continue; }
            bool f = a[1] < m;
            rep (i, 2, n) if (a[i] >= m || a[i] != (a[i - 1] + c) % m) f = 0;
            if (f) cout << m << ' ' << c << '
    ';
            else cout << "-1
    ";
        }
        return 0;
    }
    

    C - Basic Diplomacy

    注意到每个数能用(left lceil frac{m}{2} ight ceil)

    故在处理掉某天只能选一个人的情况(有解的情况下), 必定有解

    int c[N], ans[N];
    set<int> b[N];
     
    int main() {
        IOS;
        for (cin >> _; _; --_) {
            cin >> n >> m; bool f = 1;
            rep(i, 1, n) c[i] = (m + 1) >> 1;
            rep(i, 1, m) {
                ans[i] = 0; clear(b[i]);
                for (cin >> k; k; --k) cin >> cas, b[i].insert(cas);
                if (b[i].size() == 1) ans[i] = *b[i].begin(), --c[*b[i].begin()];
            }
            rep(i, 1, m) if (!ans[i]) {
                if (c[*b[i].begin()] > 0) --c[*b[i].begin()], ans[i] = *b[i].begin();
                else --c[*b[i].rbegin()], ans[i] = *b[i].rbegin();
            }
            rep (i, 1, n) if (c[i] < 0) f = 0;
            if (!f) { cout << "NO
    "; continue; }
            cout << "YES
    "; rep(i, 1, m) cout << ans[i] << ' '; cout << '
    ';
        }
        return 0;
    }
    

    D - Playlist

    两个循环队列 a, b, a为原音乐的循环队列, b维护可能删除b[i]这首歌在原队列a中下一首歌的序列

    循环检测b[i]是否能删除祁在原序列中的下一首歌

    如果能, 就把a中的那首歌删除, 如果删除的歌也在b序列, 那再b序列中也删除

    否则在b序列删除当前b[i]

    对于每首歌, 要么b[i]的时候被删除, 或者b[i]本身被删除, 总的每首歌都被从b序列删除之后停止

    故复杂度为 (O(n))

    struct node { int pre, nxt, k; } a[N], b[N];
    
    int n, m, _, k, cas;
    
    void delet(node* a, int id) {
        a[a[id].nxt].pre = a[id].pre, a[a[id].pre].nxt = a[id].nxt;
    }
    
    int main() {
        IOS;
        for (cin >> _; _; --_) {
            cin >> n; map<int, int> st; m = 0; VI ans;
            rep(i, 1, n) {
                cin >> a[i].k, b[i].pre = a[i].pre = i - 1;
                b[i].k = i; b[i].nxt = a[i].nxt = i + 1;
            }
            b[1].pre = a[1].pre = n, b[n].nxt = a[n].nxt = 1;
            for (int i = 1; ; i = b[i].nxt)
                if (__gcd(a[b[i].k].k, a[a[b[i].k].nxt].k) == 1) {
                    int bnxt = b[i].nxt;
                    if (b[bnxt].k == a[b[i].k].nxt) delet(b, bnxt);
                    ans.pb(a[b[i].k].nxt); delet(a, a[b[i].k].nxt);
                    if (i == b[bnxt].k && b[bnxt].k == a[b[i].k].nxt) break;
                }
                else { delet(b, i); if (b[i].nxt == i) break; }
            cout << ans.size() << ' ';
            for (auto& i : ans) cout << i << ' '; cout << '
    ';
        }
        return 0;
    }
    

    E Skyline Photo

    一个单调栈即可, 因为要建筑要连续, 且只有在 b[i] 在当前序列中最低才有贡献

    故维护一个单调栈, h[st.top()] > h[i] i可以和 st.top() 合并成一个序列, 且这段序列魅力值为 b[i]

    为了dp, 我们还要再维护一个mx[i] 表示 不含 当前 i 这一序列的最大值, 则

    f[i] = mx[i] + b[i]

    对于 mx[i], 首先是 mx[i] = f[i - 1]

    当 h[st.top()] > h[i] 时, i 可以合并, 则 mx[i] = max(mx[i], mx[st.top])

    最后是在 h[st.top()] < h[i] 时, 还有一种选择, b[i] 没贡献 i, f[i] = max(f[i], f[st.top()])

    const int N = 3e5 + 5;
    
    int n, m, _, k, cas;
    int h[N], b[N];
    ll f[N], mx[N];
    
    int main() {
        IOS; cin >> n; stack<int> st;
        rep(i, 1, n) cin >> h[i];
        rep(i, 1, n) cin >> b[i];
        rep(i, 1, n) {
            for (mx[i] = f[i - 1]; !st.empty() && h[st.top()] > h[i]; st.pop())
                umax(mx[i], mx[st.top()]);
            f[i] = b[i] + mx[i];
            if (!st.empty()) umax(f[i], f[st.top()]); st.push(i);
        }
        cout << f[n];
        return 0;
    }
    

    F - Useful Edges

    注意 5s 的时限

    意味着(O(n))跑了, 边和询问都是 (n^2) 的数量级, 也就是 (O(n imes m + n imes q)) 的复杂度是允许的

    先弗洛伊德跑个最短路, 毕竟这是个求最短路的问题

    对于每个询问 ((u, v, c)), 好边是 (d[u][x] + cost(x, y) + d[y][v] <= c)

    暴力的 (O(m imes q)) 是不行了, 只能想办法 (O(n imes m + n imes q))

    那就只能通过遍历 顶点 i, 来解决((i, v, c))的询问了

    对每个顶点预处理个 (g[y] = max(c_k - d[y][v_k])) 即枚举边的时候我们只用考虑 (d[i][x] + cost(x, y))

    memset(g, -1, sizeof g);
    for (auto &[y, c] : h[i]) rep (j, 1, n) umax(g[j], c - d[j][y]);
    rep (j, 1, m) if (d[i][e[j].u] + e[j].c <= g[e[j].v]) vis[j] = 1;
    

    完整代码

    struct node { int u, v, c; } e[N];
    
    int n, m, _, k, cas;
    vector<PII> h[M];
    ll d[M][M], g[M];
    bool vis[N];
    
    int main() {
        IOS; cin >> n >> m; memset(d, 0x3f, sizeof d);
        rep (i, 1, n) d[i][i] = 0;
        rep (i, 1, m) {
            cin >> e[i].u >> e[i].v >> e[i].c;
            umin(d[e[i].u][e[i].v], e[i].c); d[e[i].v][e[i].u] = d[e[i].u][e[i].v];
        }
        rep (k, 1, n) rep (i, 1, n) rep (j, 1, n) umin(d[i][j], d[i][k] + d[k][j]);
        for (cin >> _; _; --_) { int u, v, c; cin >> u >> v >> c; h[u].pb(v, c); h[v].pb(u, c); }
        rep (i, 1, n) {
            memset(g, -1, sizeof g);
            for (auto &[y, c] : h[i]) rep (j, 1, n) umax(g[j], c - d[j][y]);
            rep (j, 1, m) if (d[i][e[j].u] + e[j].c <= g[e[j].v]) vis[j] = 1;
        }
        rep (i, 1, m) k += vis[i]; cout << k;
        return 0;
    }
    
  • 相关阅读:
    [LeetCode] 769. Max Chunks To Make Sorted
    [LeetCode] 563. Binary Tree Tilt
    [LeetCode] 1802. Maximum Value at a Given Index in a Bounded Array
    [LeetCode] 1198. Find Smallest Common Element in All Rows
    [LeetCode] 370. Range Addition
    [LeetCode] 1749. Maximum Absolute Sum of Any Subarray
    [LeetCode] 1801. Number of Orders in the Backlog
    [LeetCode] 869. Reordered Power of 2
    [LeetCode] 841. Keys and Rooms
    [LeetCode] 1603. Design Parking System
  • 原文地址:https://www.cnblogs.com/2aptx4869/p/14566150.html
Copyright © 2011-2022 走看看