Submission #1135951


Source Code Expand

/+ dub.sdl:
    name "F"
    dependency "dcomp" version=">=0.6.0"
+/

import std.stdio, std.range, std.conv, std.algorithm;
import std.math;
// import dcomp.foundation;
// import dcomp.scanner;
// import dcomp.array;
// import dcomp.algorithm;

// import dcomp.twosat;
import core.bitop : bsr;

immutable INF = 10^^9 + 10^^7;

int n;
int[] pos;

//md より大きくは出来ない
bool solve(int md) {
    int[2][] v;
    foreach (int i, d; pos) {
        v ~= [d, i];
    }
    v = v.sort!((l, r) => cmp(l[], r[]) == -1).array;
    int m = v.length.to!int;
    int lg = m.bsr;
    if ((2^^lg) < m) lg++;
    m = 1<<lg;

    int getI(int i, int x) {
        return binSearch!(idx => cmp(v[idx][], [x, i].fixed[]) != -1)(-1, v.length.to!int);
    }

    auto sat = TwoSat(2*n + 2*m);
    foreach (i; 0..n) {
        // exactly 1 true
        sat.addCond(2*i, true, 2*i+1, true);
        sat.addCond(2*i, false, 2*i+1, false);
    }
    //make segtree
    foreach (i; 1..m) {
        sat.addCond(2*n+2*i, false, 2*n+i, true);
        sat.addCond(2*n+2*i+1, false, 2*n+i, true);
    }

    void query(int a, int b, int i, int l = 0, int r = m, int k = 1) {
        if (b <= l || r <= a) return;
        if (a <= l && r <= b) {
            sat.addCond(i, false, 2*n+k, false);
            return;
        }
        int md = (l+r)/2;
        query(a, b, i, l, md, 2*k);
        query(a, b, i, md, r, 2*k+1);
    }
    foreach (int i, x; pos) {
        int idx = getI(i, x);
        query(getI(-1, x-md), idx, i);
        query(idx+1, getI(INF, x+md), i);
        sat.addCond(i, false, 2*n + m + idx, true);
    }
    return sat.exec() == false;
}

int main() {
    auto sc = new Scanner(stdin);
    sc.read(n);
    pos = new int[2*n];
    pos.each!((ref x) => sc.read(x));
    writeln(binSearch!(md => solve(md))(-1, INF));
    return 0;
}
/* IMPORT /home/yosupo/Program/dcomp/source/dcomp/twosat.d */
// module dcomp.twosat;

// import dcomp.graph.scc;
// import dcomp.array;

struct TwoSat {
    bool[] res;

    struct Edge {int to;}
    import std.array;
//    Edge[][] g;
    FastAppender!(Edge[])[] g;

    // add ((a == aExp) || (b == bExp))
    void addCond(int a, bool aExp, int b, bool bExp) {
        void addEdge(int l, int r) {
            g[l] ~= Edge(r);
        }
        addEdge(2*a+(aExp?0:1), 2*b+(bExp?1:0));
        addEdge(2*b+(bExp?0:1), 2*a+(aExp?1:0));
    }
    bool exec() {
        import std.algorithm : map;
        import std.conv : to;
        int n = res.length.to!int;
        auto sccInfo = scc(g.map!(v => v.data).array);
        for (int i = 0; i < n; i++) {
            if (sccInfo.id[2*i] == sccInfo.id[2*i+1]) return false;
            res[i] = sccInfo.id[2*i] < sccInfo.id[2*i+1];
        }
        return true;
    }
    this(int n) {
        res = new bool[n];
        g = new FastAppender!(Edge[])[](2*n);
    }
}

unittest {
    import std.algorithm, std.conv, std.stdio, std.range;
    import std.random;
    import std.typecons;
    import std.datetime;

    struct E {int to;}

    writeln("TwoSat Random10000");
    void f() {
        int n = uniform(1, 50);
        int m = uniform(1, 100);
        auto ans = new bool[n];
        auto sat = TwoSat(n);
        ans.each!((ref x) => x = uniform(0, 2) == 1);
        struct N {int i; bool expect;}
        N[2][] conds;
        foreach (i; 0..m) {
            int x = uniform(0, n);
            int y = uniform(0, n);
            while (true) {
                bool f = uniform(0, 2) == 1;
                bool g = uniform(0, 2) == 1;
                if (ans[x] != f && ans[y] != g) continue;
                sat.addCond(x, f, y, g);
                conds ~= [N(x, f), N(y, g)];
                break;
            }
        }
        assert(sat.exec());
        auto res = sat.res;
        foreach (cond; conds) {
            int x = cond[0].i;
            bool f = cond[0].expect;
            int y = cond[1].i;
            bool g = cond[1].expect;
            assert(res[x] == f || res[y] == g);
        }
    }
    auto ti = benchmark!(f)(10000);
    writeln(ti[0].msecs, "ms");
}
/* IMPORT /home/yosupo/Program/dcomp/source/dcomp/graph/scc.d */
// module dcomp.graph.scc;

struct SCC {
    int[] id; // vertex id -> scc id
    int[][] groups; // scc id -> scc vertexs
    int count; // scc count
    this(int n) {
        id = new int[n];
    }
}

// import dcomp.array;

SCC scc(T)(T g) {
    import std.array : appender;
    import std.range;
    import std.algorithm : each, map;
    import std.conv : to;
    int n = g.length.to!int;
    //make reverse graph
    struct Edge {int to;}
    FastAppender!(Edge[])[] rg_buf = new FastAppender!(Edge[])[](n);
    g.each!((i, v) => v.each!(e => rg_buf[e.to] ~= Edge(i.to!int)));
    auto rg = rg_buf.map!(v => v.data).array;

    auto sccInfo = SCC(n);
    with (sccInfo) {
        auto used = new bool[n];

        //make backorder list
        auto vs = appender!(int[])();
        void dfs(int v) {
            used[v] = true;
            foreach (e; g[v]) {
                if (used[e.to]) continue;
                dfs(e.to);
            }
            vs ~= v;
        }
        foreach (i; 0..n) {
            if (used[i]) continue;
            dfs(i);
        }

        used[] = false;        
        count = 0;
        auto buf = appender!(int[])();
        void rdfs(int v) {
            used[v] = true;
            id[v] = count;
            buf ~= v;
            foreach (e; rg[v]) {
                if (used[e.to]) continue;
                rdfs(e.to);
            }
        }
        auto groups_buf = appender!(int[][])();
        foreach_reverse (i; vs.data) {
            if (used[i]) continue;
            rdfs(i);
            groups_buf ~= buf.data.dup;
            buf.clear();
            count++;
        }
        groups = groups_buf.data;
    }
    return sccInfo;
}

unittest {
    import std.algorithm, std.conv, std.stdio, std.range;
    import std.random;
    import std.typecons;
    import std.datetime;

    struct E {int to;}

    writeln("SCC Random1000");
    void f() {
        int n = uniform(1, 50);
        int p = uniform(1, 50);
        E[][] g = new E[][n];
        bool[][] naive = new bool[][](n, n);
        foreach (i; 0..n) {
            foreach (j; 0..n) {
                if (i == j) continue;
                if (uniform(0, 100) < p) {
                    g[i] ~= E(j);
                    naive[i][j] = true;
                }
            }
        }

        auto sccInfo = scc(g);

        foreach (k; 0..n) {
            foreach (i; 0..n) {
                foreach (j; 0..n) {
                    naive[i][j] |= naive[i][k] && naive[k][j];
                }
            }
        }

        foreach (i; 0..n) {
            foreach (j; i+1..n) {
                bool same = sccInfo.id[i] == sccInfo.id[j];
                if (same) {
                    assert(naive[i][j] && naive[j][i]);
                } else {
                    assert(!naive[i][j] || !naive[j][i]);                    
                    if (sccInfo.id[i] < sccInfo.id[j]) {
                        assert(!naive[j][i]);
                    } else {
                        assert(!naive[i][j]);
                    }
                }
            }
        }
    }
    auto ti = benchmark!(f)(1000);
    writeln(ti[0].msecs, "ms");
}
/* IMPORT /home/yosupo/Program/dcomp/source/dcomp/algorithm.d */
// module dcomp.algorithm;

import std.range.primitives;
import std.traits : isFloatingPoint, isIntegral;

//[0,0,0,...,1,1,1]で、初めて1となる場所を探す。pred(l) == 0, pred(r) == 1と仮定
T binSearch(alias pred, T)(T l, T r) if (isIntegral!T) {
    while (r-l > 1) {
        T md = (l+r)/2;
        if (!pred(md)) l = md;
        else r = md;
    }
    return r;
}

T binSearch(alias pred, T)(T l, T r, int cnt = 60) if (isFloatingPoint!T) {
    foreach (i; 0..cnt) {
        T md = (l+r)/2;
        if (!pred(md)) l = md;
        else r = md;
    }
    return r;
}

Rotator!Range rotator(Range)(Range r) {
    return Rotator!Range(r);
}

struct Rotator(Range)
if (isForwardRange!Range && hasLength!Range) {
    size_t cnt;
    Range start, now;
    this(Range r) {
        cnt = 0;
        start = r.save;
        now = r.save;
    }
    this(this) {
        start = start.save;
        now = now.save;
    }
    @property bool empty() {
        return now.empty;
    }
    @property auto front() {
        assert(!now.empty);
        import std.range : take, chain;
        return chain(now, start.take(cnt));
    }
    @property Rotator!Range save() {
        return this;
    }
    void popFront() {
        cnt++;
        now.popFront;
    }
}


E minimum(alias pred = "a < b", Range, E = ElementType!Range)(Range range, E seed)
if (isInputRange!Range && !isInfinite!Range) {
    import std.algorithm, std.functional;
    return reduce!((a, b) => binaryFun!pred(a, b) ? a : b)(seed, range);
}

ElementType!Range minimum(alias pred = "a < b", Range)(Range range) {
    assert(!range.empty, "range must not empty");
    auto e = range.front; range.popFront;
    return minimum!pred(range, e);
}

E maximum(alias pred = "a < b", Range, E = ElementType!Range)(Range range, E seed)
if (isInputRange!Range && !isInfinite!Range) {
    import std.algorithm, std.functional;
    return reduce!((a, b) => binaryFun!pred(a, b) ? b : a)(seed, range);
}

ElementType!Range maximum(alias pred = "a < b", Range)(Range range) {
    assert(!range.empty, "range must not empty");
    auto e = range.front; range.popFront;
    return maximum!pred(range, e);
}

unittest {
    assert(minimum([2, 1, 3]) == 1);
    assert(minimum!"a > b"([2, 1, 3]) == 3);
    assert(minimum([2, 1, 3], -1) == -1);
    assert(minimum!"a > b"([2, 1, 3], 100) == 100);

    assert(maximum([2, 1, 3]) == 3);
    assert(maximum!"a > b"([2, 1, 3]) == 1);
    assert(maximum([2, 1, 3], 100) == 100);
    assert(maximum!"a > b"([2, 1, 3], -1) == -1);
}

bool[ElementType!Range] toMap(Range)(Range r) {
    import std.algorithm : each;
    bool[ElementType!Range] res;
    r.each!(a => res[a] = true);
    return res;
}
/* IMPORT /home/yosupo/Program/dcomp/source/dcomp/scanner.d */
// module dcomp.scanner;

class Scanner {
    import std.stdio : File;
    import std.conv : to;
    import std.range : front, popFront, array, ElementType;
    import std.array : split;
    import std.traits : isSomeChar, isStaticArray, isArray; 
    import std.algorithm : map;
    File f;
    this(File f) {
        this.f = f;
    }
    string[] buf;
    private bool succ() {
        while (!buf.length) {
            if (f.eof) return false;
            buf = f.readln.split;
        }
        return true;
    }
    private bool readSingle(T)(ref T x) {
        if (!succ()) return false;
        static if (isArray!T) {
            alias E = ElementType!T;
            static if (isSomeChar!E) {
                //string or char[10] etc
                x = buf.front;
                buf.popFront;
            } else {
                static if (isStaticArray!T) {
                    //static
                    assert(buf.length == T.length);
                }
                x = buf.map!(to!E).array;
                buf.length = 0;                
            }
        } else {
            x = buf.front.to!T;
            buf.popFront;            
        }
        return true;
    }
    int read(T, Args...)(ref T x, auto ref Args args) {
        if (!readSingle(x)) return 0;
        static if (args.length == 0) {
            return 1;
        } else {
            return 1 + read(args);
        }
    }
}

unittest {
    import std.path : buildPath;
    import std.file : tempDir;
    import std.algorithm : equal;
    import std.stdio : File;
    string fileName = buildPath(tempDir, "kyuridenanmaida.txt");
    auto fout = File(fileName, "w");
    fout.writeln("1 2 3");
    fout.writeln("ab cde");
    fout.writeln("1.0 1.0 2.0");
    fout.close;
    Scanner sc = new Scanner(File(fileName, "r"));
    int a;
    int[2] b;
    char[2] c;
    string d;
    double e;
    double[] f;
    sc.read(a, b, c, d, e, f);
    assert(a == 1);
    assert(equal(b[], [2, 3]));
    assert(equal(c[], "ab"));
    assert(equal(d, "cde"));
    assert(e == 1.0);
    assert(equal(f, [1.0, 2.0]));
}
/* IMPORT /home/yosupo/Program/dcomp/source/dcomp/foundation.d */
// module dcomp.foundation;
//fold(for old compiler)
static if (__VERSION__ <= 2070) {
    template fold(fun...) if (fun.length >= 1) {
        auto fold(R, S...)(R r, S seed) {
            import std.algorithm : reduce;
            static if (S.length < 2) {
                return reduce!fun(seed, r);
            } else {
                import std.typecons : tuple;
                return reduce!fun(tuple(seed), r);
            }
        }
    }
    unittest {
        import std.stdio;
        auto l = [1, 2, 3, 4, 5];
        assert(l.fold!"a+b"(10) == 25);
    }
}
/* IMPORT /home/yosupo/Program/dcomp/source/dcomp/array.d */
// module dcomp.array;

T[N] fixed(T, int N)(T[N] a) {return a;}

//this is not reference type!(please attention to copy)
struct FastAppender(A) {
    import std.algorithm : max;
    import std.range.primitives : ElementEncodingType;
    import core.stdc.string : memcpy;

    private alias T = ElementEncodingType!A;
    private T* _data;
    private size_t len, cap;

    void reserve(size_t nlen) {
        import core.memory : GC;
        if (nlen <= cap) return;
        
        void* nx = GC.malloc(nlen * T.sizeof);            

        cap = nlen;
        if (len) memcpy(nx, _data, len * T.sizeof);
        _data = cast(T*)(nx);
    }
    void opOpAssign(string op : "~")(T item) {
        if (len == cap) {
            reserve(max(4, cap*2));
        }
        _data[len++] = item;
    }
    void clear() {
        len = 0;
    }    
    T[] data() {
        return (_data) ? _data[0..len] : null;
    }
}

unittest {
    import std.stdio, std.algorithm;
    auto u = FastAppender!(int[])();
    u ~= 4; u ~= 5;
    assert(equal(u.data, [4, 5]));
}

Submission Info

Submission Time
Task F - Flags
User yosupo
Language D (LDC 0.17.0)
Score 1200
Code Size 14526 Byte
Status AC
Exec Time 3031 ms
Memory 150964 KB

Judge Result

Set Name Sample All
Score / Max Score 0 / 0 1200 / 1200
Status
AC × 3
AC × 30
Set Name Test Cases
Sample 00_example_01.txt, 00_example_02.txt, 00_example_03.txt
All 00_example_01.txt, 00_example_02.txt, 00_example_03.txt, 01.txt, 02.txt, 03.txt, 04.txt, 05.txt, 06.txt, 07.txt, 08.txt, 09.txt, 10.txt, 11.txt, 12.txt, 13.txt, 14.txt, 15.txt, 16.txt, 17.txt, 18.txt, 19.txt, 20.txt, 21.txt, 22.txt, 23.txt, 24.txt, 25.txt, 26.txt, 27.txt
Case Name Status Exec Time Memory
00_example_01.txt AC 2 ms 508 KB
00_example_02.txt AC 2 ms 764 KB
00_example_03.txt AC 5 ms 2428 KB
01.txt AC 64 ms 9212 KB
02.txt AC 28 ms 5372 KB
03.txt AC 9 ms 3708 KB
04.txt AC 13 ms 4348 KB
05.txt AC 13 ms 4220 KB
06.txt AC 2377 ms 83708 KB
07.txt AC 2443 ms 98560 KB
08.txt AC 2404 ms 89660 KB
09.txt AC 63 ms 4092 KB
10.txt AC 26 ms 3708 KB
11.txt AC 9 ms 3964 KB
12.txt AC 13 ms 5116 KB
13.txt AC 13 ms 4860 KB
14.txt AC 2273 ms 76028 KB
15.txt AC 2226 ms 76156 KB
16.txt AC 2261 ms 75644 KB
17.txt AC 64 ms 9468 KB
18.txt AC 28 ms 3452 KB
19.txt AC 2514 ms 89264 KB
20.txt AC 2430 ms 85640 KB
21.txt AC 2788 ms 100444 KB
22.txt AC 2717 ms 118532 KB
23.txt AC 3031 ms 150964 KB
24.txt AC 2626 ms 144368 KB
25.txt AC 2558 ms 105828 KB
26.txt AC 2508 ms 99528 KB
27.txt AC 1 ms 380 KB