AtCoder Regular Contest 106

コンテスト前のレート:1702
レート通りのパフォーマンスが得られる順位:652位(1200点、50分24秒)

A - 106

問題

思考過程
  1. ABの組み合わせを全探索する。
  2. 1 \leq A, B \lt 60くらいで調べれば、探索範囲としては十分だが、オーバーフローした値が条件を満たすようなケースが用意されていたら困る。
  3. 3^13^{50}くらいまで出力してみて、何乗で10^{18}を超えるかを調べ、探索範囲を絞る。5についても同様。
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));
        long n = Long.parseLong(br.readLine());
        br.close();

        for (int a = 1; a < 39; a++) {
            for (int b = 1; b < 27; b++) {
                if (power(3, a) + power(5, b) == n) {
                    System.out.println(a + " " + b);
                    return;
                }
            }
        }
        System.out.println(-1);
    }

    // 以下ライブラリ

    static long power(long x, long n) {
        if (n == 0) {
            return 1;
        }
        long val = power(x, n / 2);
        val = val * val;
        if (n % 2 == 1) {
            val = val * x;
        }
        return val;
    }
}

ここまで4分06秒+0ペナ。296位。


B - Values

問題
ACLのDSUにgroupsがあったのを完全に忘れていた。
BFS自力実装で損した時間は3分程度だろうか。

思考過程
  1. 連結成分内では、操作を伝播させていけば合計値が変わらない中で自由に値を変えられる。
  2. つまり、連結成分ごとにaの合計とbの合計が一値していればYes。
  3. 自分のUnionFindには、連結成分に含まれる頂点の集合を取得する機能がないので、BFSで頑張ることにする。
  4. BFSの始点として全ての頂点を調べ、まだどの連結成分にも含まれていない頂点からのみBFSを行う。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;

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 m = Integer.parseInt(sa[1]);

        sa = br.readLine().split(" ");
        int[] a = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = Integer.parseInt(sa[i]);
        }
        sa = br.readLine().split(" ");
        int[] b = new int[n];
        for (int i = 0; i < n; i++) {
            b[i] = Integer.parseInt(sa[i]);
        }

        List<List<Integer>> list = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            list.add(new ArrayList<>());
        }
        for (int i = 0; i < m; i++) {
            sa = br.readLine().split(" ");
            int c = Integer.parseInt(sa[0]) - 1;
            int d = Integer.parseInt(sa[1]) - 1;
            list.get(c).add(d);
            list.get(d).add(c);
        }
        br.close();

        boolean[] used = new boolean[n];
        for (int i = 0; i < n; i++) {
            if (used[i]) {
                continue;
            }
            long suma = a[i];
            long sumb = b[i];
            Queue<Integer> que = new ArrayDeque<>();
            que.add(i);
            used[i] = true;
            while (!que.isEmpty()) {
                int cur = que.poll();
                for (int j : list.get(cur)) {
                    if (!used[j]) {
                        que.add(j);
                        used[j] = true;
                        suma += a[j];
                        sumb += b[j];
                    }
                }
            }
            if (suma != sumb) {
                System.out.println("No");
                return;
            }
        }
        System.out.println("Yes");
    }
}

ここまで10分13秒+0ペナ。171位。


C - Solutions

問題

思考過程
  1. 高橋君実装が求めているのは最適解。これは緑difficultyのキーエンス2020-B:Robot Armsが解けなくて悔しい思いをしたのを覚えていた。
  2. よって、M \lt 0の場合は-1。
     
  3. とりあえず[10:20], [30:40], [50:60], \cdotsのようなN-1個の区間を作ってみる。
  4. 青木君実装の最適でない場合を考えると、残り1個の区間[1:A]として、
    • A=2とすると、どちらもN個になってM=0
    • A=11とすると、どちらもN-1個になってM=0
    • A=31とすると、高橋君N-1個、青木君N-2個になってM=1
    • A=51とすると、高橋君N-1個、青木君N-3個になってM=2
  5. このように、Aの調節次第で0 \leq M \leq N-2を自由に構築できる。
  6. 実装上、[10:15], [20:25], [30:35], \cdotsのようにした方が、Aの計算を間違えなそうだったので、そのようにする。
     
  7. 青木君側を0個にはできないため、この方法ではM \geq N-1の場合は構築できない。
  8. 高橋君N個、青木君1個にするのも無理なので、やはりM \geq N-1の場合は無理そう。 →1ケースWA
  9. N=1, M=0の場合は構築可能であったので、-1とする条件から除く。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;

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 m = Integer.parseInt(sa[1]);
        br.close();

        if (m < 0 || (n > 1 && m >= n - 1)) {
            System.out.println(-1);
            return;
        }

        PrintWriter pw = new PrintWriter(System.out);
        for (int i = 1; i < n; i++) {
            int a = i * 10;
            pw.println(a + " " + (a + 5));
        }
        int a = m * 10 + 11;
        if (m == 0) {
            a = 2;
        }
        pw.println(1 + " " + a);
        pw.flush();
    }
}

ここまで26分09秒+1ペナ。119位。


D - Powers

問題
解けず。EとFも10分ずつくらいは考えたが無理。
_NC_2通り全部の計算をしたいけど、N \leq 10^5で愚直は無理。というタイプの問題がなかなかできるようにならない。

思考過程
  1. 愚直に計算するとO(KN^2logK)くらい。X乗の部分を繰り返し二乗法ではなく、前回の結果を残しておいてもO(KN^2)
  2. _NC_2部分については、二次元表にしてみたときに、N^2個のマスの総和から斜めを引いて半分にするとか、縦か横に上手くまとめてN^2かかるのをN+Nにするとかを考える。
  3. 後者で考え、累積和や二項係数を駆使してNを落とすことはできたが、1 \leq X \leq Kの各XについてO(XN)かかる計算になってしまったため、全体でO(K^2N)となり、TLE。

 



終結果:ABCの3完、31分09秒、459位、パフォーマンス1888
レート変動:1702→1722(+20)


なんとかレートマイナスは連続4回でストップ。
しかしまだhighestから98も下がっている状態で、そもそも5月~9月辺りはほぼ1750以上を維持していたので、早く1800前後に戻りたい。