Submission #1129315

#TimeUsernameProblemLanguageResultExecution timeMemory
1129315antonnNaan (JOI19_naan)C++20
29 / 100
495 ms32476 KiB
#include <bits/stdc++.h>


using namespace std;


#define ll long long
#define ld long double
#define all(a) a.begin(), a.end()
#define rall(a) a.rbegin(), a.rend()


int n, L;
vector<vector<int>> v;
vector<vector<ll>> pref;

struct Frac {
    ll p;
    ll q;

    Frac(ll a = 0, ll b = 1) : p(a), q(b) {}
    
    void reduct() {
        ll d = __gcd(p, q);
        p /= d;
        q /= d;
    }
};


bool operator <= (Frac a, Frac b) {
    return (__int128) a.p * b.q <= (__int128) b.p * a.q;
}


bool operator < (Frac a, Frac b) {
    return (__int128) a.p * b.q <  (__int128) b.p * a.q;
}


Frac operator + (Frac a, Frac b) {
    Frac c;
    c.p = a.p * b.q + b.p * a.q;
    c.q = a.q * b.q;
    return c;
}


Frac operator - (Frac a, Frac b) {
    Frac c;
    c.p = a.p * b.q - b.p * a.q;
    c.q = a.q * b.q;
    return c;
}


Frac operator - (ll x, Frac f) {
    return {x * f.q - f.p, f.q};
}


Frac operator - (Frac f, ll x) {
    return {f.p - x * f.q, f.q};
}


Frac operator * (Frac f, ll x) {
    f.p *= x;
    return f;
}


Frac operator / (Frac f, ll x) {
    f.q *= x;
    return f;
}


int32_t main() {
    if (1) {
        ios::sync_with_stdio(0);
        cin.tie(0);
        cout.tie(0);
    }
    cin >> n >> L;
    v.assign(n + 1, vector<int>(L + 2));
    vector<Frac> need(n + 1);
    for (int i = 1; i <= n; i += 1) {
        ll sum = 0;
        for (int j = 1; j <= L; j += 1) {
            cin >> v[i][j];
            sum += v[i][j];
        }
        v[i][L + 1] = 1;
        need[i] = {sum, n};
    }
    vector<vector<Frac>> cuts(n + 1);
    for (int i = 1; i <= n; i += 1) {
        Frac pos = {0, 1};
        Frac c = {0, 1};
        Frac sum = {0, 1};
        int full = 0;
        cuts[i].push_back({0, 1});
        while (full != L) {
            if (sum + (full + 1 - c) * v[i][full + 1] <= need[i]) {
                sum = sum + (full + 1 - c) * v[i][full + 1];
                full += 1;
                c = {full, 1};
            } else {
                c = c + (need[i] - sum) / v[i][full + 1];
                c.reduct();
                cuts[i].push_back(c);
                assert(c.p != 0);
                sum = {0, 1};
            }
        }
        cuts[i].push_back({L, 1});
    }
    vector<int> rem(n);
    iota(all(rem), 1);
    vector<pair<int, Frac>> sol;
    Frac last = {-1, 1};
    for (int it = 1; it <= n; it += 1) {
        pair<int, Frac> best = {-1, {L, 1}};
        for (int i : rem) {
            int low = 0, high = n - 1, sol = -1;
            while (low <= high) {
                int mid = (low + high) / 2;
                if (last <= cuts[i][mid]) {
                    sol = mid;
                    high = mid - 1;
                } else {
                    low = mid + 1;
                }
            }
            if (sol != -1) {
                if (cuts[i][sol + 1] <= best.second) {
                    best = {i, cuts[i][sol + 1]};
                }
            }
        }
        if (best.first == -1) {
            cout << -1 << "\n";
            return 0;
        }
        sol.push_back(best);
        vector<int> nw;
        for (auto i : rem) {
            if (i != best.first) {
                nw.push_back(i);
            }
        }
        rem = nw;
        last = best.second;
    }
    for (int i = 0; i < sol.size() - 1; i += 1) {
        int who = sol[i].first;
        Frac split = sol[i].second;
        // assert(split.p != 0);
        cout << split.p << " " << split.q << "\n";
    }
    for (int i = 0; i < sol.size(); i += 1) {
        int who = sol[i].first;
        Frac split = sol[i].second;
        cout << who << " ";
    }
    cout << "\n";
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...