zoukankan      html  css  js  c++  java
  • Deltix Round, Summer 2021 Div1 + Div2 A~E

    比赛链接:Here

    1556A. A Variety of Operations

    注意到2, 3操作不改变总和,1操作使得总和加上了一个偶数,故直接判断总和是否为偶数即可。如果和为偶数,只要判断c和d是否相等即可。注意0要判一下

    【AC Code】

    const int N = 1e5 + 7;
    int n, m, k, tot, a[N];
    int main() {
        ios::sync_with_stdio(false), cin.tie(nullptr);
        int _; for (cin >> _; _--;) {
            int c, d; cin >> c >> d;
            if (c == 0 && d == 0) {
                puts("0");
                continue;
            }
            if ((c + d) % 2 == 0) {
                if (c == d ) {
                    puts("1");
                } else puts("2");
            } else puts("-1");
        }
    }
    

    1566B. Take Your Places!

    题意:

    给一个有 (n) 个数字的数组,可以交换相邻的数字,求最小交换次数使得相邻的数奇偶性不相同。

    思路:

    先判一下奇数和偶数的个数,在按顺序分配位置就行。如果奇数和偶数个数相等,还得枚举奇数先放还是偶数先放。注意开 ll

    【AC Code】

    int main() {
        cin.tie(nullptr)->sync_with_stdio(false);
        int _; for (cin >> _; _--;) {
            int n; cin >> n;
            vector<int>a(n);
            for (int &x : a) {
                cin >> x;
                x &= 1;
            }
            ll ans = LLONG_MAX;
            for (int j = 0; j < 2; ++j) {
                vector<int>b(n);
                for (int i = 0; i < n; ++i) b[i] = (i & 1) == j;
                vector<int>la, lb;
                for (int i = 0; i < n; ++i) {
                    if (a[i]) la.push_back(i);
                    if (b[i]) lb.push_back(i);
                }
                if (la.size() != lb.size()) continue;
                ll op = 0;
                for (int i = 0; i < la.size(); ++i) op += abs(la[i] - lb[i]);
                ans = min(ans, op);
            }
            cout << (ans >= LLONG_MAX ? -1 : ans) << "
    ";
        }
    }
    

    1566C. Compressed Bracket Sequence

    莫名其妙地ac了,不是很懂。

    首先枚举左端点 (l) 和右端点 (r) ,用函数 (check(l,r)) 统计这两个端点的贡献(在 (l) 处开始,$ r$ 处结束的合法括号序列的数量)。假设每一个左括号为 (1),右括号为 (-1) ,对序列求个前缀和,方便判断是否合法。

    所有的从 (l) 开始,(r)​​ 结束的合法括号序列,不一定用了(l)​和(r)中的每一个左右括号。

    首先计算 (d=sum[r]-sum[l-1])​ ,以得出左右两边是否有多余的括号,我们要舍去。之后再枚举(l+1)(r−1)的每一个位置(i),他们必须满足(sum[i]−sum[l−1]>=0) .统计这个差值的最小值,记为 (mx) ,其表示左边 (l)处最多能有几个括号多出来。那么答案至多有(mx+1).注意当(d>0)时,这个值要减去 (d) 后才能用于更新 (mx)

    之后保险起见,还得和左边能贡献的左括号数量,右边能贡献的右括号数量取 (min),注意此时也要把$ d$ 的偏差加上去,具体见代码。

    【AC Code】

    const int N = 1e5 + 7;
    int n, m, k;
    ll tot, c[N], ans, sum[N];
    ll check(int l, int r) {
        ll d = sum[r] - sum[l - 1], mx = 99999999999999999ll;
        for (int i = l + 1; i < r; i += 2) {
            if (d <= 0)
                mx = min(mx, sum[i] - sum[l - 1]);
            if (d > 0)
                mx = min(mx, sum[i] - d - sum[l - 1]);
        }
        if (mx < 0) return 0;
        //if (mx == 0) return 1;
        if (d == 0) return min(c[l], min(mx + 1ll, -c[r]));
        if (d < 0) return min(c[l], min(mx + 1ll, -c[r] + d));
        if (d > 0) return min(c[l] - d, min(mx + 1ll, -c[r]));
    }
    int main() {
        ios::sync_with_stdio(false), cin.tie(nullptr);
        cin >> n;
        for (int i = 1; i <= n; i++) {
            cin >> c[i];
            if (i % 2 == 0) c[i] = -c[i];
            sum[i] = sum[i - 1] + c[i];
        }
        for (int l = 1; l <= n; l += 2) {
            for (int r = l + 1; r <= n; r += 2) {
                ans += check(l, r);
            }
        }
        cout << ans;
    }
    

    1566D. Take a Guess

    第一次做交互题,要频繁清空流感觉有点麻烦

    $ a+b=a & b+a mid b$ ,用 (a+b, a+c, b+c)​ 可以求出 $ a b c $ ,已知 $ a$ 和 (a & b+a mid b) 可以求 b , 这样直接求出所有的 $ a[i]$​ 就行。

    【AC Code】

    注意每一行输出之后要立刻 fflush(stdout);

    #include <bits/stdc++.h>
    using ll = long long;
    using namespace std;
    typedef pair<int, int> pii;
    #define mk make_pair
    const int maxn = 1e4 + 7;
    int rd() {
        int s = 0, f = 1; char c = getchar();
        while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
        while (c >= '0' && c <= '9') {s = s * 10 + c - '0'; c = getchar();}
        return s * f;
    }
    int n, m, k, tot;
    ll a[maxn];
    ll getPlus(int i, int j) {
        printf("or %d %d
    ", i, j);
        fflush(stdout);
        ll orij = rd();
        printf("and %d %d
    ", i, j);
        fflush(stdout);
        ll andij = rd();
        return orij + andij;
    }
    void get(int i, int j, int k) {
        ll pij = getPlus(i, j);
        ll pjk = getPlus(j, k);
        ll pik = getPlus(i, k);
        a[i] = (pij - pjk + pik) / 2ll;
        a[j] = (pjk - pik + pij) / 2ll;
        a[k] = (pik - pij + pjk) / 2ll;
    }
    int main() {
        ios::sync_with_stdio(false), cin.tie(nullptr);
        n = rd(); k = rd();
        for (int i = 1; i <= n; i += 3) {
            if (i + 2 > n) break;
            get(i, i + 1, i + 2);
        }
        if (n % 3 == 1) {
            ll p1 = getPlus(1, n);
            a[n] = p1 - a[1];
        }
        if (n % 3 == 2) {
            ll p1 = getPlus(1, n - 1);
            a[n - 1] = p1 - a[1];
            ll p2 = getPlus(1, n);
            a[n] = p2 - a[1];
        }
        sort(a + 1, a + n + 1);
        printf("finish %lld
    ", a[k]);
    }
    

    1556E. Equilibrium

    给出俩个长为 (n) 的整数序列 (a)(b)​ ,以及一些询问 $(1, mathrm{r}) (. 对于每个) (l, r) (, 回答最少要执行多少次操作,使得 ) mathrm{a}[1 ldots mathrm{r}]=mathrm{b}[1 ldots mathrm{r}] $​, 或是判断无解。
    每次操作为选取偶数个下标 (p o s_{i})​ , 满足 $ l leq p o s_{1}<p o s_{2}<cdots<p o s_{k} leq r $​, 然后让 (a) 中下标为
    $operatorname{pos}{1}, operatorname{pos}{3}, p o s_{5}, cdots, p o s_{k}-1 $ 的数 (+1) , 让 (b) 中下标为 $p o s_{2}, p o s_{4}, operatorname{pos}{6}, cdots, p o s{k} $ 的位置的数 $+1 $.
    每次询问是互相独立的。

    sol:这里参考了高Rank大佬们的思路

    思路参考

    【AC Code】

    const int maxn = 1e5 + 7;
    #define ll long long
    int n, m, k, tot, a[maxn], q;
    ll sum[maxn];
    ll stmx[22][maxn], stmi[22][maxn];
    int rd() {
        int s = 0, f = 1; char c = getchar();
        while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
        while (c >= '0' && c <= '9') {s = s * 10 + c - '0'; c = getchar();}
        return s * f;
    }
    ll querymi(int l, int r) {
        int len = r - l + 1, len2;
        for (len2 = 0; (1 << (len2 + 1)) < len; len2++);
        return min(stmi[len2][l], stmi[len2][r - (1 << len2) + 1]);
    }
    ll querymx(int l, int r) {
        int len = r - l + 1, len2;
        for (len2 = 0; (1 << (len2 + 1)) < len; len2++);
        return max(stmx[len2][l], stmx[len2][r - (1 << len2) + 1]);
    }
    int main() {
        n = rd();
        q = rd();
        //printf("%d %d
    ", n, q);
        for (int i = 1; i <= n; i++)
            a[i] = rd();
        for (int i = 1; i <= n; i++) {
            a[i] -= rd();
            sum[i] = sum[i - 1] + a[i];
            stmx[0][i] = stmi[0][i] = sum[i];
        }
        //q = rd();
        for (int j = 1; j <= 20; j++)
            for (int i = 1; i <= n - (1 << j) + 1; i++)
                stmi[j][i] = 100000000000001ll, stmx[j][i] = -100000000000001ll;
        for (int i = 1; i <= 20; i++) {
            for (int j = 1; j <= n - (1 << i) + 1; j++) {
                stmi[i][j] = min(stmi[i - 1][j], stmi[i - 1][j + (1 << (i - 1))]);
                stmx[i][j] = max(stmx[i - 1][j], stmx[i - 1][j + (1 << (i - 1))]);
            }
        }
        while (q--) {
            int l = rd();
            int r = rd();
            //printf("l == %d r == %d qmx == %lld qmi == %lld
    ", l, r, querymx(l, r)-sum[l-1], querymi(l, r)-sum[l-1]);
            if (sum[r] - sum[l - 1] != 0 || querymx(l, r) > sum[l - 1]) {
                puts("-1");
                continue;
            } else {
                printf("%lld
    ", -(querymi(l, r) - sum[l - 1]));
            }
        }
        return 0;
    }
    

    The desire of his soul is the prophecy of his fate
    你灵魂的欲望,是你命运的先知。

  • 相关阅读:
    枚举与常量需要注意的一个问题
    parted分区用法
    Linux下常用服务的端口号
    NFS服务
    mount用法
    Rsync服务部署
    常见的RAID级别
    SQL注入语句 (很全)
    数据库被注入daxia123或cn.jxmmtv.com原因及解决办法
    StringTemplate.net模板技术用法
  • 原文地址:https://www.cnblogs.com/RioTian/p/15215097.html
Copyright © 2011-2022 走看看