バイトの競プロメモ

主に競技プログラミング

E - Ball Coloring AtCoder Regular Contest 073

問題概略
2個の白いボールが入った袋がN個あり、それらには数字が書いてある。
袋のボールを赤と青に塗り分けた時、(rmax - rmin) * (bmax - bmin) を最小化したい

制約
N<=2 * 10^5
x,y <= 10^9

解法
全体の最大値、最小値は必ずどちらかに含まれる。
よって赤大 赤小 赤大 青小の2パターンがある。
後者は赤になるべく大きいものを入れ、青に小さいものを入れれば良い。
前者について考える。
わかりやすくするためx,yを左のほうが小さく、昇順になるようにする。
xをbに入れ事を考えると、現在最大値はこれより小さく出来ず、差を減らすには最小値を交換するしか無いことがわかる。
つまり、昇順にした後に上からいくつかを交換すれば良い。o(N)

Submission #3181054 - AtCoder Regular Contest 073

 public static void solve() throws Exception {
        //longを忘れるなオーバーフローするぞ
        N = ni();
        int[] x = niah(N, 2);
        int[] y = niah(N, 2);
        {
            int[] r = new int[N];
            int[] b = new int[N];
            for (int i = 0; i < N; i++) {
                r[i] = max(x[i], y[i]);
                b[i] = min(x[i], y[i]);
            }
            chMin(((long) max(r) - min(r)) * ((long) max(b) - min(b)));
        }
        {
            P[] p = new P[N];
            for (int i = 0; i < N; i++) {
                p[i] = new P(min(x[i], y[i]), max(x[i], y[i]));
            }
            sort(p);
            long maxr = max(max(x), max(y));
            long minr = min(min(x), min(y));
            SegmentTree seg = new SegmentTree(N);
            for (int i = 0; i < N; i++) {
                seg.update(i, p[i].x);
            }
            //i個入れ替える
            for (int i = 0; i < N + 1; i++) {
                if (i != 0) seg.update(i - 1, p[i - 1].y);
                chMin((maxr - minr) * ((long) seg.max(0, N) - seg.min(0, N)));
            }
        }
        System.out.println(minRes);
    }