Atcoder-ABC372

-
-
2024-09-22

Rank:2600

A. 题目链接

没有思路,直接模拟。

B. 题目链接

算法标签:枚举。

思路:枚举N,i。用一个变量sum统计 power(3, i) 的和,如果sum等于m了,则找到一个合法方案,直接输出即可。

public static void solve() throws IOException {
        int m = in.nextInt();
        int[] A = new int[20];
        int sum = 0;
        int N = 0;
        for (int i = 10; i >= 0; i--) {
            int power = (int)Math.pow(3, i);
            while (sum + power <= m && N < 20) {
                A[N++] = i;
                sum += power;
            }
            if (sum == m) {
                break;
            }
        }
        out.println(N);
        for (int i = 0; i < N; i++) {
            out.print(A[i] + " ");
        }
        out.println();
    }

C. 题目链接

算法标签:模拟、枚举。

思路:先统计s种所有ABC子串的个数记作cnt。根据题目要求模拟,如果修改的字符会影响组成ABC子串的字符,那么cnt--,然后将x位置的字符替换为c,再重新遍x的附近位置,检查是否会形成新的ABC子串,如果有则cnt++。

public static void solve() throws IOException {
        int n = in.nextInt();
        int q = in.nextInt();
        String s = in.nextLine();
        int cnt = 0;
        for (int i = 0; i < n - 2; i++) {
            String t = s.substring(i, i + 3);
            if (t.equals("ABC")) {
               cnt++;
            }
        }
        List<Integer> ans = new ArrayList<>();
        char[] cs = s.toCharArray();
        while (q-- > 0) {
            String line = in.nextLine();
            String[] ss = line.split(" ");
            int x = Integer.parseInt(ss[0]) - 1;
            char c = ss[1].charAt(0);

            int start = Math.max(0, x - 2);
            int end = Math.min(n - 1, x + 2);

            for (int i = start; i < end - 1; i++) {
                if (cs[i] == 'A' && cs[i+1] == 'B' && cs[i+2] == 'C') {
                    cnt--;
                }
            }
            cs[x] = c;
            for (int i = start; i < end - 1; i++) {
                if (cs[i] == 'A' && cs[i+1] == 'B' && cs[i+2] == 'C') {
                    cnt++;
                }
            }
            ans.add(cnt);

        }
        for (int v : ans) {
            out.println(v);
        }
    }

D. 题目链接

算法标签:单调栈。

思路:倒着枚举i,如果栈顶元素小于当前元素的下一个值,那么就要pop栈顶。比如 2 5 4 这种,4肯定是要被pop的。ans[i]就是stk.size()。

public static void solve() throws IOException {
        int n = in.nextInt();
        int[] h = new int[n];
        for (int i = 0; i < n; i++) {
            h[i] = in.nextInt();
        }
        int[] ans = new int[n];
        var stk = new ArrayDeque<Integer>();
        for (int i = n - 2; i >= 0; i--) {
            // 如果栈顶元素 < 当前值的下一个值 就要pop
            while (!stk.isEmpty() && h[stk.peek()] < h[i + 1]) {
                stk.pop();
            }
            stk.push(i + 1);
            ans[i] = stk.size();
        }
        for (int v : ans) out.print(v + " ");
        out.println();
    }

E. 题目链接

算法标签:并查集、启发式合并、排序。

思路:因为k很小(1≤k≤10),用并查集实现点与点的合并,并且每个连通分量要维护前k大的元素。如果当前联通分量的元素个数超过10了,就要poll。query的时候把并查集维护的元素取出来排个序,取第k大就行了。

思考:如果k很大,应该怎么做。

public static void solve() throws IOException {
        int n = in.nextInt();
        int q = in.nextInt();
        List<Integer> ans = new ArrayList<>();
        UnionFind uf = new UnionFind(n);
        while (q-- > 0) {
            String[] s = in.nextLine().split(" ");
            int op = Integer.parseInt(s[0]);
            if (op == 1) {
                int u = Integer.parseInt(s[1]);
                int v = Integer.parseInt(s[2]);
                uf.merge(u, v);
            } else {
                int v = Integer.parseInt(s[1]);
                int k = Integer.parseInt(s[2]); // k很小,只有10

                int root = uf.find(v);
                PriorityQueue<Integer> pq = uf.pqs[root];
                if (pq.size() < k) {
                    ans.add(-1);
                    continue;
                }
                List<Integer> list = new ArrayList<>(pq);
                list.sort((x, y) -> y - x);
                ans.add(list.get(k - 1));
            }
        }
        for (int v : ans) {
            out.println(v);
        }
    }

    static class UnionFind {
        int[] fa;
        PriorityQueue<Integer>[] pqs;

        public UnionFind(int n) {
            this.fa = new int[n + 1]; // n+1
            this.pqs = new PriorityQueue[n + 1];
            for (int i = 1; i <= n; ++i) {
                fa[i] = i;
                pqs[i] = new PriorityQueue<>((a, b) -> a - b);
                pqs[i].add(i);
            }

        }

        // 非递归版本 查询 (路径压缩版)
        public int find(int x) {
            while (x != fa[x]) {
                fa[x] = fa[fa[x]];
                x = fa[x];
            }
            return x;
        }

        // 合并
        public void merge(int from, int to) {
            int x = find(from);
            int y = find(to);
            if (x == y) return;
            if (pqs[x].size() > pqs[y].size()) {
                for (int v : pqs[y]) {
                    pqs[x].add(v);
                    if (pqs[x].size() > 10) pqs[x].poll();
                }
                fa[y] = x;
            } else {
                for (int v : pqs[x]) {
                    pqs[y].add(v);
                    if (pqs[y].size() > 10) pqs[y].poll();
                }
                fa[x] = y;
            }
        }
    }

梅狸猫
meilicat
公告

随便看看就好~