1
0

洛谷-P15653.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. #include <algorithm>
  2. #include <cstdint>
  3. #include <iostream>
  4. #include <numeric>
  5. #include <utility>
  6. #include <vector>
  7. // Standalone local-protocol version. The official submission keeps solve_case
  8. // and replaces the final verifier by calls to report() and invert().
  9. struct Result {
  10. int maximum_edges = 0;
  11. std::vector<std::vector<int>> operations;
  12. };
  13. namespace {
  14. using Matrix = std::vector<std::vector<unsigned char>>;
  15. void toggle_clique(Matrix& difference, const std::vector<int>& vertices) {
  16. for (std::size_t i = 0; i < vertices.size(); ++i) {
  17. for (std::size_t j = i + 1; j < vertices.size(); ++j) {
  18. int u = vertices[i];
  19. int v = vertices[j];
  20. difference[u][v] ^= 1;
  21. difference[v][u] ^= 1;
  22. }
  23. }
  24. }
  25. void add_operation(Matrix& difference, std::vector<std::vector<int>>& operations,
  26. std::vector<int> vertices) {
  27. toggle_clique(difference, vertices);
  28. for (int& vertex : vertices) ++vertex; // local matrix is zero-indexed
  29. operations.push_back(std::move(vertices));
  30. }
  31. Matrix make_best_target(const Matrix& initial, int k, int& maximum_edges) {
  32. int n = static_cast<int>(initial.size());
  33. int complete_edges = n * (n - 1) / 2;
  34. int edge_count = 0;
  35. std::vector<int> degree_parity(n, 0);
  36. for (int u = 0; u < n; ++u) {
  37. for (int v = u + 1; v < n; ++v) {
  38. if (initial[u][v]) {
  39. ++edge_count;
  40. degree_parity[u] ^= 1;
  41. degree_parity[v] ^= 1;
  42. }
  43. }
  44. }
  45. Matrix missing(n, std::vector<unsigned char>(n, 0));
  46. auto add_missing = [&](int u, int v) {
  47. missing[u][v] = missing[v][u] = 1;
  48. };
  49. int residue = k % 4;
  50. if (residue == 0) {
  51. if (((complete_edges - edge_count) & 1) != 0) add_missing(0, 1);
  52. } else if (residue == 1 || residue == 3) {
  53. std::vector<int> odd;
  54. for (int vertex = 0; vertex < n; ++vertex) {
  55. int required_missing_parity = ((n - 1) & 1) ^ degree_parity[vertex];
  56. if (required_missing_parity) odd.push_back(vertex);
  57. }
  58. for (std::size_t i = 0; i < odd.size(); i += 2)
  59. add_missing(odd[i], odd[i + 1]);
  60. if (residue == 1) {
  61. int required_edge_parity = (complete_edges - edge_count) & 1;
  62. int current_missing = static_cast<int>(odd.size() / 2);
  63. if ((current_missing & 1) != required_edge_parity) {
  64. if (odd.empty()) {
  65. add_missing(0, 1);
  66. add_missing(1, 2);
  67. add_missing(2, 0);
  68. } else {
  69. int first = odd[0];
  70. int second = odd[1];
  71. int middle = 0;
  72. while (middle == first || middle == second) ++middle;
  73. missing[first][second] = missing[second][first] = 0;
  74. add_missing(first, middle);
  75. add_missing(middle, second);
  76. }
  77. }
  78. }
  79. }
  80. Matrix target(n, std::vector<unsigned char>(n, 0));
  81. int missing_count = 0;
  82. for (int u = 0; u < n; ++u) {
  83. for (int v = u + 1; v < n; ++v) {
  84. target[u][v] = target[v][u] = missing[u][v] ^ 1;
  85. missing_count += missing[u][v];
  86. }
  87. }
  88. maximum_edges = complete_edges - missing_count;
  89. return target;
  90. }
  91. bool finish_k_plus_two(Matrix& difference, const std::vector<int>& remaining,
  92. std::vector<std::vector<int>>& operations) {
  93. int h = static_cast<int>(remaining.size());
  94. std::vector<int> degree(h, 0);
  95. for (int i = 0; i < h; ++i)
  96. for (int j = i + 1; j < h; ++j)
  97. if (difference[remaining[i]][remaining[j]]) degree[i] ^= 1, degree[j] ^= 1;
  98. for (int total_parity = 0; total_parity < 2; ++total_parity) {
  99. std::vector<int> incident_parity(h, 0);
  100. bool possible = true;
  101. if ((h & 1) == 0) {
  102. for (int i = 0; i < h; ++i)
  103. incident_parity[i] = degree[i] ^ total_parity;
  104. } else {
  105. for (int value : degree) possible = possible && value == 0;
  106. }
  107. if (!possible) continue;
  108. std::vector<std::pair<int, int>> selected;
  109. int actual_total = 0;
  110. for (int i = 0; i < h; ++i) {
  111. for (int j = i + 1; j < h; ++j) {
  112. int use = difference[remaining[i]][remaining[j]] ^ total_parity ^
  113. incident_parity[i] ^ incident_parity[j];
  114. if (use) selected.push_back({i, j}), actual_total ^= 1;
  115. }
  116. }
  117. if (actual_total != total_parity) continue;
  118. Matrix trial = difference;
  119. for (auto [left_out, right_out] : selected) {
  120. std::vector<int> clique;
  121. for (int i = 0; i < h; ++i)
  122. if (i != left_out && i != right_out) clique.push_back(remaining[i]);
  123. toggle_clique(trial, clique);
  124. }
  125. bool zero = true;
  126. for (int i = 0; i < h; ++i)
  127. for (int j = i + 1; j < h; ++j)
  128. zero = zero && trial[remaining[i]][remaining[j]] == 0;
  129. if (!zero) continue;
  130. for (auto [left_out, right_out] : selected) {
  131. std::vector<int> clique;
  132. for (int i = 0; i < h; ++i)
  133. if (i != left_out && i != right_out) clique.push_back(remaining[i]);
  134. add_operation(difference, operations, std::move(clique));
  135. }
  136. return true;
  137. }
  138. return false;
  139. }
  140. Result solve_case(const Matrix& initial, int k) {
  141. int n = static_cast<int>(initial.size());
  142. Result result;
  143. Matrix target = make_best_target(initial, k, result.maximum_edges);
  144. Matrix difference = initial;
  145. for (int u = 0; u < n; ++u)
  146. for (int v = u + 1; v < n; ++v)
  147. difference[u][v] = difference[v][u] = initial[u][v] ^ target[u][v];
  148. std::vector<int> remaining(n);
  149. std::iota(remaining.begin(), remaining.end(), 0);
  150. const int subset_size = k - 1;
  151. while (static_cast<int>(remaining.size()) > k + 2) {
  152. int vertex = remaining.back();
  153. remaining.pop_back();
  154. std::vector<int> universe = remaining;
  155. std::vector<int> base(universe.begin(), universe.begin() + subset_size);
  156. std::vector<int> outside(universe.begin() + subset_size, universe.end());
  157. int base_zero = base[0];
  158. int outside_zero = outside[0];
  159. int outside_other_xor = 0;
  160. for (std::size_t i = 1; i < outside.size(); ++i)
  161. outside_other_xor ^= difference[vertex][outside[i]];
  162. int base_rest_xor = 0;
  163. for (int i = 1; i < subset_size; ++i)
  164. base_rest_xor ^= difference[vertex][base[i]];
  165. int total_coefficient = 0;
  166. if (subset_size & 1) {
  167. int a_zero = difference[vertex][outside_zero] ^ base_rest_xor;
  168. int all_a = a_zero ^ outside_other_xor;
  169. total_coefficient = difference[vertex][base_zero] ^ all_a;
  170. }
  171. std::vector<int> a(outside.size(), 0);
  172. std::vector<int> c(subset_size, 0);
  173. for (std::size_t i = 1; i < outside.size(); ++i)
  174. a[i] = difference[vertex][outside[i]];
  175. int all_c = ((subset_size - 1) & 1) * total_coefficient ^ base_rest_xor;
  176. a[0] = difference[vertex][outside_zero] ^ all_c;
  177. for (int i = 1; i < subset_size; ++i)
  178. c[i] = total_coefficient ^ difference[vertex][base[i]];
  179. int all_a = 0;
  180. for (int value : a) all_a ^= value;
  181. int base_coefficient = total_coefficient ^ all_a ^ all_c;
  182. if (base_coefficient) {
  183. std::vector<int> clique = base;
  184. clique.push_back(vertex);
  185. add_operation(difference, result.operations, std::move(clique));
  186. }
  187. for (std::size_t i = 0; i < outside.size(); ++i) {
  188. if (!a[i]) continue;
  189. std::vector<int> clique = base;
  190. clique[0] = outside[i];
  191. clique.push_back(vertex);
  192. add_operation(difference, result.operations, std::move(clique));
  193. }
  194. for (int i = 1; i < subset_size; ++i) {
  195. if (!c[i]) continue;
  196. std::vector<int> clique = base;
  197. clique[i] = outside_zero;
  198. clique.push_back(vertex);
  199. add_operation(difference, result.operations, std::move(clique));
  200. }
  201. }
  202. if (!finish_k_plus_two(difference, remaining, result.operations)) {
  203. result.maximum_edges = -1; // This can only indicate a construction bug.
  204. }
  205. return result;
  206. }
  207. } // namespace
  208. int main() {
  209. std::ios::sync_with_stdio(false);
  210. std::cin.tie(nullptr);
  211. int test_point, test_cases;
  212. std::cin >> test_point >> test_cases;
  213. (void)test_point;
  214. while (test_cases--) {
  215. int n, m, k, operation_limit;
  216. std::cin >> n >> m >> k >> operation_limit;
  217. Matrix graph(n, std::vector<unsigned char>(n, 0));
  218. for (int i = 0; i < m; ++i) {
  219. int u, v;
  220. std::cin >> u >> v;
  221. --u;
  222. --v;
  223. graph[u][v] = graph[v][u] = 1;
  224. }
  225. Result result = solve_case(graph, k);
  226. bool valid = result.maximum_edges >= 0 &&
  227. static_cast<int>(result.operations.size()) <= operation_limit;
  228. for (const auto& operation : result.operations) {
  229. valid = valid && static_cast<int>(operation.size()) == k;
  230. std::vector<int> zero_indexed = operation;
  231. for (int& vertex : zero_indexed) --vertex;
  232. toggle_clique(graph, zero_indexed);
  233. }
  234. int final_edges = 0;
  235. for (int u = 0; u < n; ++u)
  236. for (int v = u + 1; v < n; ++v) final_edges += graph[u][v];
  237. valid = valid && final_edges == result.maximum_edges;
  238. std::cout << result.maximum_edges << ' ' << (valid ? 1 : 0) << '\n';
  239. }
  240. return 0;
  241. }