バイトの競プロメモ

主に競技プログラミング

E - Or Plus Max AtCoder Regular Contest 100

問題概略

長さ2^Nの数列がある。
(i | j) <= K の時 Ai + A jの最大値を任意のKについて求めよ。

制約
N <= 18
Ai < 10^9

解法
i or j が K以下ということについて考える時、i or j が0の時、1の時、...Kの時という風に分けて考えたくなる。(使い回せるし)
i or j が K となるものを列挙するのは難しいが、今回知りたいのはK以下のものなので、i,jをKの部分集合とすれば良い。
よって部分集合をまとめ上げられる高速ゼータ変換を使う。

public static void solve() {
        //longを忘れるなオーバーフローするぞ
        N = ni();
        int size = (1 << N);
        A = nia(size);
        P[] p = new P[size];
        for (int i = 0; i < size; i++) {
            p[i] = new P(A[i], 0);
        }
        //sの部分集合を総和する
        for (int i = 0; i < N; i++) {
            for (int s = 0; s < size; s++) {
                if (bitIsTrue(s, i)) {
                    merge(p[s], p[s ^ (1 << i)]);
                }
            }
        }
        for (int i = 1; i < size; i++) {
            chMax(p[i].x + p[i].y);
            System.out.println(maxRes);
        }
    }

    public static void merge(P p1, P p2) {
        int[] v = new int[4];
        v[0] = p1.x;
        v[1] = p1.y;
        v[2] = p2.x;
        v[3] = p2.y;
        revSort(v);
        p1.x = v[0];
        p1.y = v[1];
    }