QOJ.ac

QOJ

IDSubmission IDProblemHackerOwnerResultSubmit timeJudge time
#961#635663#9458. Triangulationhos_lyricucup-team4435Success!2024-10-13 17:26:532024-10-13 17:26:57

Details

Extra Test:

Time Limit Exceeded

input:

70
18
0 999919
1 999936
2 999951
3 999964
4 999975
5 999984
6 999991
7 999996
8 999999
9 1000000
10 999999
11 999996
12 999991
13 999984
14 999975
15 999964
16 999951
17 999936
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0...

output:


result:


IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#635663#9458. Triangulationucup-team4435#TL 85ms79068kbC++2011.3kb2024-10-12 20:32:192024-10-13 18:02:34

answer

#include "bits/stdc++.h"

#ifdef LOCAL
    #include "debug.h"
#else
    #define dbg(...)
    #define dprint(...)
    #define debug if constexpr (false)
    #define draw_tree(...)
    #define draw_array(...)
#endif // LOCAL

#define rep(i, n) for (int i = 0; i < (n); ++i)
#define rep1(i, n) for (int i = 1; i < (n); ++i)
#define rep1n(i, n) for (int i = 1; i <= (n); ++i)
#define repr(i, n) for (int i = (n) - 1; i >= 0; --i)
#define pb push_back
#define eb emplace_back
#define all(a) (a).begin(), (a).end()
#define rall(a) (a).rbegin(), (a).rend()
#define each(x, a) for (auto &x : a)
#define ar array
#define vec vector
#define range(i, n) rep(i, n)

using namespace std;

using ll = long long;
using ull = unsigned long long;
using ld = long double;
using str = string;
using pi = pair<int, int>;
using pl = pair<ll, ll>;

using vi = vector<int>;
using vl = vector<ll>;
using vpi = vector<pair<int, int>>;
using vvi = vector<vi>;

int Bit(int mask, int b) { return (mask >> b) & 1; }

template<class T>
bool ckmin(T &a, const T &b) {
    if (b < a) {
        a = b;
        return true;
    }
    return false;
}

template<class T>
bool ckmax(T &a, const T &b) {
    if (b > a) {
        a = b;
        return true;
    }
    return false;
}

// [l, r)
template<typename T, typename F>
T FindFirstTrue(T l, T r, const F &predicat) {
    --l;
    while (r - l > 1) {
        T mid = l + (r - l) / 2;
        if (predicat(mid)) {
            r = mid;
        } else {
            l = mid;
        }
    }
    return r;
}


template<typename T, typename F>
T FindLastFalse(T l, T r, const F &predicat) {
    return FindFirstTrue(l, r, predicat) - 1;
}


const ll INF = 2e18;
const int INFi = 2e9;

bool Equal(ll A, ll B) {
    return A == B;
}

bool Less(ll A, ll B) {
    return A < B;
}

bool Greater(ll A, ll B) {
    return A > B;
}

bool LessOrEqual(ll A, ll B) {
    return A <= B;
}

bool GreaterOrEqual(ll A, ll B) {
    return A >= B;
}

const ld EPS = 1e-9;

bool Equal(ld A, ld B) {
    return abs(A - B) < EPS;
}

bool Less(ld A, ld B) {
    return A + EPS < B;
}

bool Greater(ld A, ld B) {
    return A > B + EPS;
}

bool LessOrEqual(ld A, ld B) {
    return A <= B + EPS;
}

bool GreaterOrEqual(ld A, ld B) {
    return A + EPS >= B;
}

template<typename T, typename Q>
bool LessOrEqual(T A, Q B) {
    using C = std::common_type_t<T, Q>;
    return LessOrEqual(static_cast<C>(A), static_cast<C>(B));
}

template<typename T, typename Q>
bool Equal(T A, Q B) {
    using C = std::common_type_t<T, Q>;
    return Equal(static_cast<C>(A), static_cast<C>(B));
}

template<typename T, typename Q>
bool Less(T A, Q B) {
    using C = std::common_type_t<T, Q>;
    return Less(static_cast<C>(A), static_cast<C>(B));
}

template<typename T, typename Q>
bool Greater(T A, Q B) {
    using C = std::common_type_t<T, Q>;
    return Greater(static_cast<C>(A), static_cast<C>(B));
}

template<typename T, typename Q>
bool GreaterOrEqual(T A, Q B) {
    using C = std::common_type_t<T, Q>;
    return GreaterOrEqual(static_cast<C>(A), static_cast<C>(B));
}

template<typename T>
ll sgn(T x) {
    if (Equal(x, 0)) return 0;
    return Less(x, 0) ? -1 : 1;
}


template<typename T>
struct Point {
    T x;
    T y;

    Point(T x_ = 0, T y_ = 0) : x(x_), y(y_) {}

    template<typename Q>
    Point(const Point<Q> &other) {
        x = static_cast<T>(other.x);
        y = static_cast<T>(other.y);
    }


    template<typename Q>
    Point(Point<Q> &&other) {
        x = static_cast<T>(other.x);
        y = static_cast<T>(other.y);
    }

    template<typename Q>
    Point<std::common_type_t<T, Q>> operator+(const Point<Q> &oth) const {
        return Point{x + oth.x, y + oth.y};
    }

    template<typename Q>
    Point<std::common_type_t<T, Q>> operator-(const Point<Q> &oth) const {
        return {x - oth.x, y - oth.y};
    }

    template<typename Q>
    bool operator==(const Point<Q> &oth) const {
        return x == oth.x && y == oth.y;
    }

    template<typename Q>
    bool operator<(const Point<Q> &oth) const {
        return make_pair(x, y) < make_pair(oth.x, oth.y);
    }

    template<typename Q>
    requires (is_integral_v<Q> || is_floating_point_v<Q>)
    Point<std::common_type_t<Q, T>> operator*(const Q &b) const {
        return {x * b, y * b};
    }


    template<typename Q>
    requires (is_integral_v<Q> || is_floating_point_v<Q>)
    Point<ld> operator/(const Q &b) const {
        return {(ld) x / b, (ld) y / b};
    }

    template<typename Q>
    std::common_type_t<Q, T> operator*(const Point<Q> &oth) const {
        return x * oth.y - y * oth.x;
    }

    template<typename Q>
    std::common_type_t<Q, T> operator%(const Point<Q> &oth) const {
        return x * oth.x + y * oth.y;
    }

    Point &operator+=(const Point &other) {
        x += other.x;
        y += other.y;
        return *this;
    }

    Point &operator-=(const Point &other) {
        x -= other.x;
        y -= other.y;
        return *this;
    }

    friend ostream &operator<<(ostream &stream, const Point &P) {
        stream << P.x << ' ' << P.y;
        return stream;
    }


    friend istream &operator>>(istream &stream, Point &P) {
        stream >> P.x >> P.y;
        return stream;
    }
};

template<typename T>
Point<T> rotateCW(const Point<T> &P) {
    return {P.y, -P.x};
}

template<typename T>
Point<T> rotateCCW(const Point<T> &P) {
    return {-P.y, P.x};
}

template<typename T, typename Q>
bool Equal(const Point<T> &a, const Point<Q> &b) {
    return Equal(a.x, b.x) && Equal(a.y, b.y);
}

template<typename T, typename Q>
bool Less(const Point<T> &a, const Point<Q> &b) {
    if (!Equal(a.x, b.x)) return Less(a.y, b.y);
    return Less(a.y, b.y);
}

template<typename T, typename Q>
bool Greater(const Point<T> &a, const Point<Q> &b) {
    if (!Equal(a.x, b.x)) return Greater(a.y, b.y);
    return Greater(a.y, b.y);
}

template<typename T>
Point<T> operator-(const Point<T> &a) {
    return {-a.x, -a.y};
}


template<typename T>
T len2(const Point<T> &a) {
    return a % a;
}

template<typename T>
ld len(const Point<T> &a) {
    return sqrtl(len2(a));
}

template<typename T, typename Q>
T dist2(const Point<T> &a, const Point<Q> &b) {
    return len2(a - b);
}

template<typename T, typename Q>
ld dist(const Point<T> &a, const Point<Q> &b) {
    return len(a - b);
}

using pt = Point<ll>;

template<typename T, typename U>
bool VComp(const Point<T> &a, const Point<U> &b) {
    bool upA = a.y > 0 || (a.y == 0 && a.x >= 0);
    bool upB = b.y > 0 || (b.y == 0 && b.x >= 0);
    if (upA != upB) return upA;
    auto val = a * b;
    if (val != 0) return val > 0;
    return len2(a) < len2(b);
}

template<typename T, typename U>
bool VCompNoLen(const Point<T> &a, const Point<U> &b) {
    bool upA = a.y > 0 || (a.y == 0 && a.x >= 0);
    bool upB = b.y > 0 || (b.y == 0 && b.x >= 0);
    if (upA != upB) return upA;
    auto val = a * b;
    return val > 0;
}


const int LG = 18;
const int N = 1 << LG;

pair<ll, ll> dp[N][LG];
bool valid[LG][LG][LG];

void add(int i, int j, pair<ll, ll> ways, ll cost) {
    ways.first += cost;
    if (dp[i][j].first < ways.first) return;
    if (dp[i][j].first > ways.first) {
        dp[i][j].first = ways.first;
        dp[i][j].second = 0;
    }
    dp[i][j].second += ways.second;
}

int GetBit(int mask, int b) {
    return (mask >> b) & 1;
}

vector<pt> a;
vector<vl> w;
int n;
vi was;

pair<ll, ll> solve(int mask, int b) {
    if (dp[mask][b].second != -1) return dp[mask][b];
    was.push_back(mask);
    dp[mask][b].second = 0;

    int pr = b - 1;
    int nx = b + 1;
    while (pr >= 0 && !GetBit(mask, pr)) pr--;
    while (nx < n && !GetBit(mask, nx)) nx++;

    if (nx != n) {
        add(mask, b, solve(mask, nx), 0);
        for(int t = b + 1; t < nx; ++t) {
            if (valid[b][t][nx] && (a[nx] - a[b]) * (a[t] - a[b]) > 0) {
                add(mask, b, solve(mask ^ (1 << t), b), w[t][nx] + w[t][b]);
                dbg(mask, b, dp[mask][b], t);
            }
        }
        if (pr != -1) {
            if (valid[pr][b][nx] && (a[b] - a[pr]) * (a[nx] - a[pr]) > 0) {
                add(mask, b, solve(mask ^ (1 << b), pr), w[pr][nx]);
                dbg(mask, b, dp[mask][b], -1);
            }
        }
    }
    dbg(mask, b, dp[mask][b]);
    return dp[mask][b];
}

template<typename T>
bool inside(Point<T> a, Point<T> b, Point<T> c, Point<T> d) {
    auto area = [&](auto v1, auto v2) {
        return abs(v1 * v2);
    };
    return area(b - a, c - a) == area(a - d, b - d) + area(b - d, c - d) + area(c - d, a - d);
}

void solve() {
    cin >> n;
    a.resize(n);
    rep(i, n) cin >> a[i];

    w.assign(n, vl(n));
    rep(i, n) {
        rep(j, n) {
            cin >> w[i][j];
        }
    }

    {
        vi ord(n);
        iota(all(ord), 0);
        sort(all(ord), [&](const int &i, const int &j) { return a[i] < a[j]; });

        vector<pt> b(n);
        rep(i, n) b[i] = a[ord[i]];
        vector<vl> ww(n, vl(n));
        rep(i, n) {
            rep(j, n) {
                ww[i][j] = w[ord[i]][ord[j]];
            }
        }
        swap(a, b);
        swap(w, ww);
    }

    memset(valid, 0, sizeof(valid));
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            for (int k = j + 1; k < n; k++) {
                bool ok = true;
                for (int x = 0; x < n; x++) {
                    if (x == i || x == j || x == k) {
                        continue;
                    }
                    if (inside(a[i], a[j], a[k], a[x])) {
                        ok = false;
                        break;
                    }
                }
                valid[i][j][k] = ok;
            }
        }
    }

    {
        vi stk;
        stk.push_back(0);
        for (int i = 1; i < n; ++i) {
            while (stk.size() >= 2 &&
                   (a[stk[stk.size() - 1]] - a[stk[stk.size() - 2]]) * (a[i] - a[stk[stk.size() - 2]]) > 0) {
                stk.pop_back();
            }
            stk.push_back(i);
        }
        int mask = 0;
        for (auto &i: stk) mask |= (1 << i);
        dp[mask][n - 1] = {0, 1};
        was.push_back(mask);
    }
    {
        vi stk;
        stk.push_back(0);
        for (int i = 1; i < n; ++i) {
            while (stk.size() >= 2 &&
                   (a[stk[stk.size() - 1]] - a[stk[stk.size() - 2]]) * (a[i] - a[stk[stk.size() - 2]]) < 0) {
                stk.pop_back();
            }
            stk.push_back(i);
        }
        int mask = 0;
        for (auto &i: stk) mask |= (1 << i);
        ll res = 0;
        for(int i = 1; i < stk.size(); ++i) res += w[stk[i - 1]][stk[i]];

        auto ans = solve(mask, 0);
        ans.first += res;
        cout << ans.first << ' ' << ans.second << '\n';
    }


    for(auto &mask : was) {
        rep(i, n) dp[mask][i] = {INF, -1};
    }
    was.clear();
}

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout << setprecision(12) << fixed;
    int t = 1;
    rep(i, N) rep(j, LG) dp[i][j] = {INF, -1};

    cin >> t;
    rep(i, t) {
        solve();
    }
    return 0;
}