Submission #404808

# Submission time Handle Problem Language Result Execution time Memory
404808 2021-05-15T04:13:54 Z rama_pang Friends (BOI17_friends) C++17
0 / 100
11 ms 452 KB
#include <bits/stdc++.h>
using namespace std;

int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);

  int N, P, Q;
  cin >> N >> P >> Q;

  const auto Impossible = [&]() {
    cout << "detention\n";
    exit(0);
  };

  vector<vector<int>> adj(N);
  vector<vector<int>> mat(N, vector<int>(N));
  for (int i = 0; i < N; i++) {
    int p;
    cin >> p;
    while (p--) {
      int j;
      cin >> j;
      mat[i][j] = 1;
      adj[i].emplace_back(j);
    }
  }

  for (int i = 0; i < N; i++) {
    for (int j = 0; j < N; j++) {
      if (mat[i][j] != mat[j][i]) {
        Impossible();
      }
    }
  }

  // Solution:
  // Consider finding a group for a node u. For every node v
  // not adjacent to u, we don't need to consider them (since
  // it will only increase Q unnecessarily). For every node v
  // adjacent to u, either we pick v (and increase current p)
  // or we don't pick v (and increase current q). This way,
  // we have around 2^{P + Q} total options.
  //
  // We find a group for every node u. This runs in O(N (P + Q) 2^{P + Q}).
  // Then, for every pair of nodes, consider the 2 groups of these
  // nodes. If they arent' disjoint, we want to split them so they
  // are. We can note that:
  //
  // p1, p2 <= P, q1, q2 <= Q
  // Let p3 = intersection of (p1, p2).
  // Then:
  // q1 + edges[p1][p3] <= Q
  // q2 + edges[p3][p2] <= Q.
  // So, min(q1 + edges[p3][p2], q2 + edges[p1][p3]) <= Q.
  //
  // So, we can always split them into disjoint groups. We repair
  // all groups this way in O(N^2 * (P + Q)).
  //
  // Time complexity: O(N * (P + Q) * (N + 2^{P + Q})).

  vector<int> cur;
  vector<int> state;

  const auto GetGroup = [&](const auto &self, int cur_head, int ptr, int p, int q, vector<int> &res) {
    if (p > P || q > Q) return;
    if (!res.empty()) return;
    if (cur_head == p) { // found group
      res = cur;
      return;
    }

    int u = cur[cur_head];
    if (adj[u].size() == ptr) {
      return self(self, cur_head + 1, 0, p, q, res);
    }

    int v = adj[u][ptr];
    if (state[v] == 0) { // v is undecided
      state[v] = -1;
      self(self, cur_head, ptr + 1, p, q + 1, res);
      state[v] = +1;
      cur.emplace_back(v);
      self(self, cur_head, ptr + 1, p + 1, q, res);
      cur.pop_back();
      state[v] = 0;
    } else if (state[v] == -1) { // we already decided not to pick this node
      return self(self, cur_head, ptr + 1, p, q + 1, res);
    } else if (state[v] == +1) { // we already picked this node in group
      return self(self, cur_head, ptr + 1, p, q, res);
    }
  };

  vector<vector<int>> inGroup(N);
  for (int u = 0; u < N; u++) {
    state.assign(N, 0);
    cur = {u};
    state[u] = 1;
    GetGroup(GetGroup, 0, 0, 1, 0, inGroup[u]);
    if (inGroup[u].empty()) {
      Impossible();
    }
  }

  const auto NoIntersection = [&](const vector<int> &A, const vector<int> &B) {
    static vector<int> who(N);
    for (auto i : A) who[i] = 0;
    for (auto i : B) who[i] = 0;
    for (auto i : A) who[i] |= 1;
    for (auto i : B) who[i] |= 2;
    for (auto i : A) if (who[i] == 3) return false;
    for (auto i : B) if (who[i] == 3) return false;
    return true;
  };

  const auto FixGroup = [&](int x, int y) {
    static vector<int> who(N);
    for (auto i : inGroup[x]) who[i] = 0;
    for (auto i : inGroup[y]) who[i] = 0;

    for (auto i : inGroup[x]) who[i] |= 1;
    for (auto i : inGroup[y]) who[i] |= 2;

    vector<int> xA, yA;
    vector<int> xB, yB;

    for (auto i : inGroup[x]) {
      if (who[i] == 1) {
        xA.emplace_back(i);
        xB.emplace_back(i);
      } else {
        xA.emplace_back(i);
      }
    }

    for (auto i : inGroup[y]) {
      if (who[i] == 2) {
        yA.emplace_back(i);
        yB.emplace_back(i);
      } else {
        yA.emplace_back(i);
      }
    }

    if (NoIntersection(xA, yB)) {
      inGroup[x] = xA;
      inGroup[y] = yB;
    } else if (NoIntersection(xB, yA)) {
      inGroup[x] = xB;
      inGroup[y] = yA;
    } else {
      return false;
    }
    return true;
  };

  state.assign(N, 0);
  for (int i = 0; i < N; i++) {
    for (int j = i + 1; j < N; j++) {
      assert(FixGroup(i, j));
    }
  }

  vector<vector<int>> answer;
  for (int i = 0; i < N; i++) {
    if (!inGroup[i].empty()) {
      answer.emplace_back(inGroup[i]);
    }
  }

  cout << "home\n";
  cout << answer.size() << '\n';
  for (auto &a : answer) {
    sort(begin(a), end(a));
    cout << a.size();
    for (auto i : a) cout << ' ' << i;
    cout << '\n';
  }
  return 0;
}

Compilation message

friends.cpp: In instantiation of 'main()::<lambda(const auto:23&, int, int, int, int, std::vector<int>&)> [with auto:23 = main()::<lambda(const auto:23&, int, int, int, int, std::vector<int>&)>]':
friends.cpp:99:46:   required from here
friends.cpp:74:23: warning: comparison of integer expressions of different signedness: 'std::vector<int>::size_type' {aka 'long unsigned int'} and 'int' [-Wsign-compare]
   74 |     if (adj[u].size() == ptr) {
      |         ~~~~~~~~~~~~~~^~~~~~
# Verdict Execution time Memory Grader output
1 Correct 1 ms 204 KB Output is correct
2 Correct 1 ms 204 KB Output is correct
3 Correct 1 ms 204 KB Output is correct
4 Correct 1 ms 204 KB Output is correct
5 Incorrect 1 ms 204 KB Output isn't correct
6 Halted 0 ms 0 KB -
# Verdict Execution time Memory Grader output
1 Correct 1 ms 204 KB Output is correct
2 Correct 11 ms 452 KB Output is correct
3 Incorrect 6 ms 432 KB Output isn't correct
4 Halted 0 ms 0 KB -
# Verdict Execution time Memory Grader output
1 Correct 1 ms 204 KB Output is correct
2 Correct 11 ms 452 KB Output is correct
3 Incorrect 6 ms 432 KB Output isn't correct
4 Halted 0 ms 0 KB -
# Verdict Execution time Memory Grader output
1 Correct 1 ms 204 KB Output is correct
2 Correct 1 ms 204 KB Output is correct
3 Correct 1 ms 204 KB Output is correct
4 Correct 1 ms 204 KB Output is correct
5 Incorrect 1 ms 204 KB Output isn't correct
6 Halted 0 ms 0 KB -