モノグサプログラミングコンテスト2022(AtCoder Beginner Contest 238)(Rated範囲外)

コンテスト前のレート:2074
(Ratedだとしたら)レート通りのパフォーマンスが得られる順位:306位(2000点、95分33秒)

A - Exponential or Quadratic

問題

思考過程
  1. nが十分大きければ2^n \gt n^2だが、小さい時は微妙なので、n \le 6の時の値を全部書き出してみる。
  2. 以下より、n=1n \ge 5の場合条件を満たすことがわかる。
     2^n  n^2
n=1    2    1
n=2    4    4
n=3    8    9
n=4   16   16
n=5   32   25
n=6   64   36
import java.util.Scanner;

public class Main {
    public static void main(String[] args) throws Exception {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        sc.close();

        if (n == 1 || n >= 5) {
            System.out.println("Yes");
        } else {
            System.out.println("No");
        }
    }
}

ここまで2分14秒+0ペナ。1032位。


B - Pizza

問題

思考過程
  1. 少し見方を変えれば、長さ360の円環に距離A_iごとに切れ込みを入れる操作を行っているとみなすことができる。
  2. 切れ込みが入っているかどうかを長さ360のboolean型配列で持ってもよいが、切れ込みの位置の集合を持っておいた方が、位置の差を計算しやすそう。
import java.util.Scanner;
import java.util.TreeSet;

public class Main {
    public static void main(String[] args) throws Exception {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] a = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = sc.nextInt();
        }
        sc.close();

        TreeSet<Integer> set = new TreeSet<>();
        int x = 0;
        set.add(0);
        set.add(360);
        for (int i = 0; i < n; i++) {
            x += a[i];
            x %= 360;
            set.add(x);
        }

        Integer[] arr = set.toArray(new Integer[0]);
        int ans = 0;
        for (int i = 1; i < arr.length; i++) {
            ans = Math.max(ans, arr[i] - arr[i - 1]);
        }
        System.out.println(ans);
    }
}

ここまで6分32秒+0ペナ。369位。


C - digitnum

問題

思考過程
  1. 1桁の数は9個、2桁の数は90個、\cdotsのように1桁増えるごとに個数は10倍になっていく。
  2. Nから9を引いて答えに19の和を加算する。
    Nから90を引いて答えに190の和を加算する。
    \cdots
    のような繰り返し処理ができる。
  3. ただし、i回目の操作で9 \times 10^{i-1}を下回った場合は1Nの和を求めて終了する。
import java.util.Scanner;

public class Main {
    public static void main(String[] args) throws Exception {
        Scanner sc = new Scanner(System.in);
        long n = sc.nextLong();
        sc.close();

        int mod = 998244353;
        long a = 9;
        long ans = 0;
        while (n > 0) {
            if (n <= a) {
                ans += n % mod * (n % mod + 1) / 2;
                ans %= mod;
                break;
            }
            ans += a % mod * (a % mod + 1) / 2;
            ans %= mod;
            n -= a;
            a *= 10;
        }
        System.out.println(ans);
    }
}

ここまで15分00秒+0ペナ。280位。


D - AND and SUM

問題

思考過程
  1. x, yは、a2進数で表した時に1となる桁は共に1であり、0となる桁は両方0か片方のみ1である必要がある。
  2. その高々一方が1となる部分を単一の数cで表すとすると、x = a + cy = aより、s = 2a + cとなり、c = s - 2aとなる。
  3. ca1となる桁が重複していなければ"Yes"。
  4. 2数の1である桁が重複していないかは、ANDを取って0かどうかで判定できる。
import java.io.PrintWriter;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) throws Exception {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        PrintWriter pw = new PrintWriter(System.out);
        for (int z = 0; z < t; z++) {
            long a = sc.nextLong();
            long s = sc.nextLong();

            long b = a * 2;
            long c = s - b;
            if (c >= 0 && (a & c) == 0) {
                pw.println("Yes");
            } else {
                pw.println("No");
            }
        }
        pw.flush();
        sc.close();
    }
}

ここまで21分05秒+0ペナ。206位。


E - Range Sums

問題

思考過程
  1. なんとなくUnionFindっぽさを感じて仕方がない。
  2. ただし例3のようにたった1つの情報で"Yes"となることもあり得るので、全体が連結になる必要があるわけではない。
  3. 0NN+1個の点を持ち、(l_i, r_i)ではl_i-1r_iを連結することにし、最終的に0Nが同一連結成分になっていれば"Yes"となりそう。
  4. 例えば0-7間と0-3間の値がわかれば、3-7間の値も求められるようになることから、確かに0-3-7の任意の2点間の値を求められるようになっている。
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] sa = br.readLine().split(" ");
        int n = Integer.parseInt(sa[0]);
        int q = Integer.parseInt(sa[1]);

        UnionFind uf = new UnionFind(n + 1);
        for (int i = 0; i < q; i++) {
            sa = br.readLine().split(" ");
            int l = Integer.parseInt(sa[0]) - 1;
            int r = Integer.parseInt(sa[1]);
            uf.union(l, r);
        }
        br.close();

        if (uf.same(0, n)) {
            System.out.println("Yes");
        } else {
            System.out.println("No");
        }
    }

    // 以下ライブラリ

    static class UnionFind {
        int[] parent, size;
        int num = 0; // 連結成分の数

        UnionFind(int n) {
            parent = new int[n];
            size = new int[n];
            num = n;
            for (int i = 0; i < n; i++) {
                parent[i] = i;
                size[i] = 1;
            }
        }

        void union(int x, int y) {
            int px = find(x);
            int py = find(y);
            if (px != py) {
                parent[px] = py;
                size[py] += size[px];
                num--;
            }
        }

        int find(int x) {
            if (parent[x] == x) {
                return x;
            }
            parent[x] = find(parent[x]);
            return parent[x];
        }

        /**
         * xとyが同一連結成分か
         */
        boolean same(int x, int y) {
            return find(x) == find(y);
        }

        /**
         * xを含む連結成分のサイズ
         */
        int size(int x) {
            return size[find(x)];
        }
    }
}

ここまで27分34秒+0ペナ。121位。



残り時間はFとGを半々くらいでやっていたがどちらも解けず。

Fはyを選ぶ時はxも必要という関係でグラフを作るなんてことをやっていて、DPをするにも人の集合を持たずにできる方法がわからなかった。

Gは素数の種類数\times Nの情報を扱うTLE解法しか思い付かず。



終結果:ABCDEの5完1500点、27分34秒、388位、パフォーマンス1980相当
レート変動:2074(Unrated)


なんかUnionFindをちょっと捻っただけくらいの問題はあまり労せず解けることが多いが、やはりDPが足を引っ張っている感じ。
今回はDPができなかったというより初手で違う方向に行き過ぎてしまった感じもするけど。

最近序盤からコケ過ぎだったので、Eまで十分早く解けたことは良かった。