• Codeforces Round #783 (Div. 2)


    Codeforces Round #783 (Div. 2)

    A - Direction Change

    保证让\(n \geq m\), 只要\(m > 1\) 在第二维上就可以反复横跳,则必定有解

    int main() {
        IOS;
        for (cin >> _; _; --_) {
            cin >> n >> m;
            if (m > n) swap(n, m);
            if (n - m > 1 && m < 2) cout << -1 << '\n';
            else if (n - m < 2) cout << n + m - 2 << '\n';
            else if (n - m & 1) cout << 2 * n - 3 << '\n';
            else cout << 2 * n - 2 << '\n';
        }
        return 0;
    }
    

    B - Social Distance

    先拆环

    假设最后一个人坐在最后一个位置,则第一人必定坐在\(max(a_n, a_1) + 1\)的位置上,这样才能保证两人在换上相隔人数合法,

    之后下一个人的位置\(s_i = s_{i - 1} + max(a_{i -1}, a_i) + 1\),只要保证最后一个人位置不超过拆环的序列长度即可,

    假定$a_0 = a_n, b_i = max(a_{i - 1}, a_i) $

    然后就是贪心,使得两人之间所需空位差距尽量最小,排个序即可

    int main() {
        IOS;
        for (cin >> _; _; --_) {
            cin >> n >> m;
            bool f = 1;
            for (int i = 1; i <= n; ++i) cin >> a[i];
            sort(a + 1, a + 1 + n);
            a[0] = a[n];
            for (int i = 1; i <= n; ++i) b[i] = max(a[i], a[i - 1]);
            for (int i = 1, j = 0; i <= n && f; ++i) {
                j += b[i] + 1;
                if (j > m) f = 0;
            }
            cout << (f ? "YES" : "NO") << '\n';
        }
        return 0;
    }
    

    C - Make it Increasing

    模拟题意暴力即可,必定存在一个位置\(i\)不用操作,且其前面的数都要进行 减 操作,其后面的数都需要 加 操作,

    暴力去枚举这个\(i\)即可

    int main() {
        IOS;
        cin >> n;
        for (int i = 1; i <= n; ++i) cin >> a[i];
        long long mx = 2e18;
        for (int i = 1; i <= n; ++i) {
            long long cur = 0, ls = 0;
            for (int j = i - 1; j; --j) {
                long long c = ls / a[j] + 1;
                cur += c; ls = a[j] * c;  
            }
            ls = 0;
            for (int j = i + 1; j <= n; ++j) {
                long long c = ls / a[j] + 1;
                cur += c; ls = a[j] * c;  
            }
            umin(mx, cur);
        }
        cout << mx;
        return 0;
    }
    

    D - Optimal Partition

    dp, \(f_i\) 表示以\(i\)结尾分割后的最大值,则

    \(f_i = \left\{\begin{matrix} max(f_j + i - j)& \sum_{k = 1}^i a_k > \sum_{k = 1}^j a_k\\ max(f_j) & \sum_{k = 1}^i a_k = \sum_{k = 1}^j a_k\\ max(f_j - i + j) & \sum_{k = 1}^i a_k < \sum_{k = 1}^j a_k \end{matrix}\right. \quad i > j \geq 0\)

    \(\left\{\begin{matrix} f_i - i = max(f_j - j)& \sum_{k = 1}^i a_k > \sum_{k = 1}^j a_k\\ f_i = max(f_j) & \sum_{k = 1}^i a_k = \sum_{k = 1}^j a_k\\ f_i + i= max(f_j + j) & \sum_{k = 1}^i a_k < \sum_{k = 1}^j a_k \end{matrix}\right. \quad i > j \geq 0\)

    一维偏序用for循环搞定,对于前缀和的偏序可以通过数轴映射,离散化在数轴上表示前缀和

    再随便找数据结构维护数轴上的 \(f_i - i, f_i, f_i + i\) 的区间最值信息即可

    本人选择线段树,一棵即能维护这三种信息在区间最值的信息

    const int N = 5e5 + 5;
     
    struct BIT {
        struct node {
            int l, r, val[3];
        } tr[N << 2];
        void build(int p, int l, int r) {
            tr[p] = {l, r, {-1000000, -1000000, -1000000}};
            if (l == r) return;
            int mid = l + r >> 1;
            build(p << 1, l, mid); build(p << 1 | 1, mid + 1, r);
        }
        void change(int p, int k, int v, int id) {
            if (tr[p].l == k && tr[p].r == k) {
                umax(tr[p].val[0], v - id);
                umax(tr[p].val[1], v);
                umax(tr[p].val[2], v + id);
                return;
            }
            int mid = tr[p].l + tr[p].r >> 1;
            if (mid >= k) change(p << 1, k, v, id);
            else change(p << 1 | 1, k, v, id);
            rep(i, 0, 2) umax(tr[p].val[i], max(tr[p << 1].val[i], tr[p << 1 | 1].val[i]));
        }
        int ask(int p, int l, int r, int k) {
            if (tr[p].l >= l && tr[p].r <= r) return tr[p].val[k];
            int mid = tr[p].l + tr[p].r >> 1;
            if (mid >= r) return ask(p << 1, l, r, k);
            else if (mid < l) return ask(p << 1 | 1, l, r, k);
            return max(ask(p << 1, l, r, k), ask(p << 1 | 1, l, r, k));
        }
    } bit;
     
    int n, m, _, k, cas;
    long long a[N], b[N];
     
    int main() {
        IOS;
        for (cin >> _; _; --_) {
            cin >> n;
            vector<long long> c(1, 0);
            for (int i = 1; i <= n; ++i)
                cin >> a[i], c.emplace_back(a[i] += a[i - 1]); 
            sort(all(c)); c.erase(unique(all(c)), c.end());
            m = c.size();
            for (int i = 1; i <= n; ++i) b[i] = lower_bound(all(c), a[i]) - c.begin() + 1;
            bit.build(1, 1, m);
     
            int cur;
            bit.change(1, lower_bound(all(c), 0) - c.begin() + 1, 0, 0);
            for (int i = 1, ls = 0; i <= n; ++i, ls = cur) {
                cur = (a[i] - a[i - 1] > 0 ? 1 : a[i] - a[i - 1] < 0 ? -1 : 0) + ls;
                long long t = bit.ask(1, b[i], b[i], 1);
                umax(cur, bit.ask(1, b[i], b[i], 1));
                if (b[i] > 1) umax(cur, bit.ask(1, 1, b[i] - 1, 0) + i);
                if (b[i] < m) umax(cur, bit.ask(1, b[i] + 1, m, 2) - i);
                bit.change(1, b[i], cur, i);
            }
            cout << cur << '\n';
        }
        return 0;
    }
    

    E - Half Queen Cover

    不考虑斜着。则就是\(n\)个半皇后占据\(n\)\(n\)列,考虑斜着,也就是\(k\)个半皇后形成的对角线正好拼成了一g个\((n - k) \times (n - k)\)的矩形

    如图,\(k = 7\) 半皇后用行列覆盖了\(k \times k\)矩形,并额外还覆盖到了肉色的两个矩形,并通过\(n - k\)条对角线覆盖了\((n - k) \times (n - k)\)的矩形

    边长为\(n - k\)的正方形有\((n - k) * 2 - 1\) 条对角线,则 \(k \geq 2 \times n - 2 \times k - 1\)

    \(k = \left \lceil \frac{2n - 1}{3} \right \rceil\), 之后就是构造\(k\)个半皇后覆盖\(k * k\)矩形的问题

    int main() {
        IOS;
        cin >> n; m = (2 * n + 1) / 3;
        cout << m << '\n';
        for (int i = 1, j = 1; i <= m; ++i, j += 2) {
            if (j > m) j = 2;
            cout << i << ' ' << j << '\n';
        }
        return 0;
    }
    
  • 相关阅读:
    Linux下利用rsync实现多服务器文件同步
    SVN使用import导入新数据到版本库
    SVN协同开发时服务端与线上APACHE测试环境网站同步记录 转
    [转]rsync的配置与应用
    Matrix 旋转mc 注册点在mc的左上角
    多边形面积计算
    【神奇的代码】
    【碰撞回弹】
    三角函数
    判断点是否在线段或直线上
  • 原文地址:https://www.cnblogs.com/2aptx4869/p/16171365.html
Copyright © 2020-2023  润新知