Codeforces Round #789 (Div. 2) A~E

A Tokitsukaze and All Zero Sequence

直接贪心即可


bool v[1010];
signed main() {
    cf {
        memset(v, 0, sizeof v);
        n = read();
        cnt = 0;
        bool flag = 0;
        rep(i, 1, n) {
            a = read();
            if (v[a]) flag = 1;
            if (a == 0) cnt++;
            v[a] = 1;
        }
        if (cnt)
            cout << n - cnt << "\n";
        else if (flag) {
            cout << n << "\n";
        } else
            cout << n + 1 << "\n";
    }
    return 0;
}

B1 Tokitsukaze and Good 01-String (easy version)

贪心 观察 发现 奇数位置和偶数位置不同的话就需要操作一次

B2 Tokitsukaze and Good 01-String (hard version)

在B1的条件下,最小化不同的一堆0/一堆1的个数

那么对字符串某处 只有0/1两种选择

又要让连续的尽可能长,自然想到DP

状态转移的部分代码比较繁琐,但是好懂,将就着看


char s[N];
int f[N][2];
//前i个 ,结尾0/1串的 min操作数
//如果 i-2 i-3 一样都是0/1 他们不会被改变
signed main() {
    cf {
        n = read();
        ans = 0;
        scanf("%s", s + 1);
        for (int i = 2; i <= n; i += 2) {
            if (s[i] != s[i - 1]) ans++;
        }
        cout << ans << " ";
        for (int i = 2; i <= n; i += 2) {
            f[i][0] = f[i][1] = INF;
        }
        f[0][0] = f[0][1] = 1;
        for (int i = 2; i <= n; i += 2) {
            if (s[i] == s[i - 1]) {
                if (s[i] == '1') {
                    if (f[i - 2][1] == INF)
                        f[i][1] = f[i - 2][0] + 1;
                    else if (f[i - 2][0] == INF)
                        f[i][1] = f[i - 2][1];
                    else {
                        f[i][1] = min(f[i - 2][1], f[i - 2][0] + 1);
                    }
                } else {
                    if (f[i - 2][1] == INF)
                        f[i][0] = f[i - 2][0];
                    else if (f[i - 2][0] == INF)
                        f[i][0] = f[i - 2][1] + 1;
                    else {
                        f[i][0] = min(f[i - 2][1] + 1, f[i - 2][0]);
                    }
                }

            } else {
                if (f[i - 2][1] == INF) {
                    f[i][1] = f[i - 2][0] + 1;
                    f[i][0] = f[i - 2][0];
                } else if (f[i - 2][0] == INF) {
                    f[i][1] = f[i - 2][1];
                    f[i][0] = f[i - 2][1] + 1;
                } else {
                    f[i][1] = min(f[i - 2][1], f[i - 2][0] + 1);
                    f[i][0] = min(f[i - 2][0], f[i - 2][1] + 1);
                }
            }
        }
        cout << min(f[n][0], f[n][1]) << "\n";
    }
    return 0;
}

C Tokitsukaze and Strange Inequality

一眼看上去就像某次leetcode周赛的好三元组

但是变成了四元

思路就是枚举c和d 暴力 加 前缀和 可过

这里顺手写了个树状数组

int u[N];
int c1[N], c2[N];

int ask(int a) {
    int rs = 0;
    for (; a; a -= lowbit(a)) {
        rs += c1[a];
    }
    return rs;
}
void add(int a, int b) {
    for (; a <= n; a += lowbit(a)) {
        c1[a] += b;
    }
    return;
}

int askc(int a) {
    int rs = 0;
    for (; a; a -= lowbit(a)) {
        rs += c2[a];
    }
    return rs;
}
void addc(int a, int b) {
    for (; a <= n; a += lowbit(a)) {
        c2[a] += b;
    }
    return;
}
signed main() {
    cf {
        n = read();
        rep(i, 1, n) u[i] = read();
        add(u[1], 1);
        addc(u[n], 1);
        ans = 0;
        rep(b, 2, n - 1) {
            rep(i, b + 1, n - 1) { addc(u[i], 1); }
            rep(c, b + 1, n - 1) {
                // n^2枚举b c
                addc(u[c], -1);
                // cout << ask(u[c] - 1) << " " << (askc(n) - askc(u[b])) << "\n";
                ans += ask(u[c] - 1) * askc(u[b] - 1);
            }
            add(u[b], 1);
        }
        cout << ans << "\n";
        rep(i, 1, n) c1[i] = 0, c2[i] = 0;
    }
    return 0;
}

D Tokitsukaze and Meeting

贪心/DP

见注释 身为div2D相对简单了些吧 列相当好想 行有点dp的感觉


char s[N];
int as[N];
int as2[N];
signed main() {
    cf {
        //如果是不同行 同列的 那么 后面无论怎么添加数 都是 同列的 所以有 1 就是1了
        //所以在第一行满的时候 插新数 是 1 ans不变 如果 队尾是1  ans也不变 队尾0且新进的是1 ans++

        n = read();
        m = read();
        t = n * m;
        ans = 0;
        scanf("%s", s + 1);
        queue q;
        rep(i, 1, m) {
            q.push(s[i] - '0');
            if (s[i] == '1') ans++;
            as[i] = ans;
            if (as[i]) as2[i]++;
        }
        rep(i, m + 1, t) {
            int now = q.front();
            q.pop();
            if (now == 0 && s[i] == '0') {
                q.push(0);
                as[i] = as[i - 1];
            }
            if (now == 1 && s[i] == '0') {
                q.push(1);
                as[i] = as[i - 1];
            }
            if (now == 0 && s[i] == '1') {
                q.push(1);
                as[i] = as[i - 1] + 1;
            }
            if (now == 1 && s[i] == '1') {
                q.push(1);
                as[i] = as[i - 1];
            }
        }
        //以上列
        //下面考虑行
       // 经过m个数的插入之后 相当于当前的整个区域往下移了一格 
       // 那么只要新进来的m个数有一个1 就可以ans+1 简单的dp一下就可以了
        int sum = 0;
        rep(i, 1, m) if (s[i] == '1') sum++;
        rep(i, m + 1, t) {
            as2[i] = as2[i - m];
            sum -= s[i - m] - '0';
            sum += s[i] - '0';
            if (sum) as2[i]++;
        }  // i~i-m有1 就加1
        rep(i, 1, t) cout << as[i] + as2[i] << " ";
        cout << "\n";
        rep(i, 1, t) as[i] = 0, as2[i] = 0;
    }
    return 0;
}

[点击并拖拽以移动]
​

E Tokitsukaze and Two Colorful Tapes

就最近哪场div2吧好像也有个循环节问题

求和绝对值最大 那么一定是到n的 毕竟不会减小答案

然后这里并查集找环了 暴力找环也是可以的

然后确定了环 贪心的让相邻的差的最多就可以了

int ca[N], cb[N];
int f[N];
int find(int x) {
    if (x == f[x]) return x;
    return f[x] = find(f[x]);
}
map p;
vector v;
signed main() {
    cf {
        n = read();
        p.clear();
        ans = 0;
        rep(i, 1, n) ca[i] = read();
        rep(i, 1, n) f[i] = i;
        rep(i, 1, n) {
            cb[i] = read();
            a = find(ca[i]);
            b = find(cb[i]);
            if (a != b) f[a] = b;
        }
        rep(i, 1, n) { p[find(ca[i])]++; }
        int l = 1, r = n;  //染色的最小/大值
        for (auto [_, cntt] : p) {
            int kk = cntt;
            if (kk == 1) continue;
            v.clear();
            if (kk & 1) kk--;
            rep(i, 1, kk) {
                if (i & 1)
                    v.push_back(r--);
                else
                    v.push_back(l++);
            }
            for (int i = 1; i < kk; i++)
                ans += abs(v[i] - v[i - 1]);
            ans += abs(v[kk - 1] - v[0]);
        }
        cout << ans << "\n";
    }
    return 0;
}

要注意:奇环最后一个是暂时不赋值的 因为他对答案没有影响

而若先赋值了 会让之后的最小/大值 不是是真正的最小/大值

这题主要问题就在这里了 提前赋值会让贪心策略失败

你可能感兴趣的:(蓝桥杯,算法)