洛谷-P9167.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. #include <algorithm>
  2. #include <cstdint>
  3. #include <iostream>
  4. #include <limits>
  5. #include <utility>
  6. #include <vector>
  7. using int64 = std::int64_t;
  8. namespace {
  9. constexpr int MOD = 998244353;
  10. int original_vertices;
  11. int difference_limit;
  12. int total_nodes;
  13. int timer_value;
  14. std::vector<std::vector<std::pair<int, int>>> graph;
  15. std::vector<std::vector<int>> block_cut_tree;
  16. std::vector<int> discovery;
  17. std::vector<int> low;
  18. std::vector<int> vertex_stack;
  19. void build_block_cut_tree(int vertex, int parent_edge) {
  20. discovery[vertex] = low[vertex] = ++timer_value;
  21. vertex_stack.push_back(vertex);
  22. for (auto [next, edge_id] : graph[vertex]) {
  23. if (!discovery[next]) {
  24. build_block_cut_tree(next, edge_id);
  25. low[vertex] = std::min(low[vertex], low[next]);
  26. if (low[next] >= discovery[vertex]) {
  27. ++total_nodes;
  28. while (true) {
  29. int current = vertex_stack.back();
  30. vertex_stack.pop_back();
  31. block_cut_tree[total_nodes].push_back(current);
  32. block_cut_tree[current].push_back(total_nodes);
  33. if (current == next) break;
  34. }
  35. block_cut_tree[total_nodes].push_back(vertex);
  36. block_cut_tree[vertex].push_back(total_nodes);
  37. }
  38. } else if (edge_id != parent_edge) {
  39. low[vertex] = std::min(low[vertex], discovery[next]);
  40. }
  41. }
  42. }
  43. std::vector<int> subtree_size;
  44. std::vector<int> maximum_part;
  45. int centroid = 0;
  46. void find_original_centroid(int vertex, int parent) {
  47. subtree_size[vertex] = vertex <= original_vertices ? 1 : 0;
  48. maximum_part[vertex] = 0;
  49. for (int next : block_cut_tree[vertex]) {
  50. if (next == parent) continue;
  51. find_original_centroid(next, vertex);
  52. subtree_size[vertex] += subtree_size[next];
  53. maximum_part[vertex] = std::max(maximum_part[vertex], subtree_size[next]);
  54. }
  55. maximum_part[vertex] =
  56. std::max(maximum_part[vertex], original_vertices - subtree_size[vertex]);
  57. if (vertex <= original_vertices &&
  58. (centroid == 0 || maximum_part[vertex] < maximum_part[centroid]))
  59. centroid = vertex;
  60. }
  61. std::vector<int> order;
  62. std::vector<std::vector<int>> rooted_children;
  63. void root_tree(int vertex, int parent) {
  64. order.push_back(vertex);
  65. subtree_size[vertex] = vertex <= original_vertices ? 1 : 0;
  66. for (int next : block_cut_tree[vertex]) {
  67. if (next == parent) continue;
  68. rooted_children[vertex].push_back(next);
  69. root_tree(next, vertex);
  70. subtree_size[vertex] += subtree_size[next];
  71. }
  72. }
  73. std::vector<int> ways;
  74. void calculate_sizes_zero(int component_size) {
  75. for (auto iterator = order.rbegin(); iterator != order.rend(); ++iterator) {
  76. int vertex = *iterator;
  77. if (subtree_size[vertex] < component_size) continue;
  78. if (vertex <= original_vertices) {
  79. int accumulated = 1;
  80. bool exists = true;
  81. for (int child : rooted_children[vertex]) {
  82. if (subtree_size[child] < component_size)
  83. accumulated += subtree_size[child];
  84. else if (ways[child] == 0)
  85. exists = false;
  86. }
  87. ways[vertex] = accumulated == component_size && exists;
  88. } else {
  89. ways[vertex] = 1;
  90. for (int child : rooted_children[vertex]) {
  91. if (subtree_size[child] < component_size || ways[child] == 0) {
  92. ways[vertex] = 0;
  93. break;
  94. }
  95. }
  96. }
  97. if (subtree_size[vertex] > component_size + 1 && ways[vertex] == 0) {
  98. ways[centroid] = 0;
  99. break;
  100. }
  101. }
  102. }
  103. void calculate_sizes_one(int component_size) {
  104. for (auto iterator = order.rbegin(); iterator != order.rend(); ++iterator) {
  105. int vertex = *iterator;
  106. if (subtree_size[vertex] < component_size) continue;
  107. if (vertex <= original_vertices) {
  108. int accumulated = 1;
  109. int product = 1;
  110. int one_large_choice = 0;
  111. for (int child : rooted_children[vertex]) {
  112. if (subtree_size[child] < component_size) {
  113. accumulated += subtree_size[child];
  114. } else if (subtree_size[child] == component_size) {
  115. if (ways[child] != 0)
  116. ++one_large_choice;
  117. else
  118. accumulated += component_size;
  119. } else {
  120. product = static_cast<int>(static_cast<int64>(product) *
  121. ways[child] % MOD);
  122. }
  123. }
  124. ways[vertex] = 0;
  125. if (component_size <= accumulated && accumulated <= component_size + 1)
  126. ways[vertex] = product;
  127. if (accumulated == 1)
  128. ways[vertex] = static_cast<int>((ways[vertex] +
  129. static_cast<int64>(product) * one_large_choice) % MOD);
  130. } else {
  131. ways[vertex] = 1;
  132. for (int child : rooted_children[vertex]) {
  133. if (subtree_size[child] < component_size) {
  134. ways[vertex] = 0;
  135. break;
  136. }
  137. ways[vertex] = static_cast<int>(static_cast<int64>(ways[vertex]) *
  138. ways[child] % MOD);
  139. }
  140. }
  141. if (subtree_size[vertex] > component_size + 1 && ways[vertex] == 0) {
  142. ways[centroid] = 0;
  143. break;
  144. }
  145. }
  146. }
  147. int solve_exact_or_adjacent(int component_size, int limit) {
  148. std::fill(ways.begin(), ways.end(), 0);
  149. if (limit == 0) {
  150. if (original_vertices % component_size != 0) return 0;
  151. calculate_sizes_zero(component_size);
  152. return ways[centroid];
  153. }
  154. calculate_sizes_one(component_size);
  155. int adjacent = ways[centroid];
  156. if (original_vertices % (component_size + 1) == 0) {
  157. std::fill(ways.begin(), ways.end(), 0);
  158. calculate_sizes_zero(component_size + 1);
  159. adjacent -= ways[centroid];
  160. if (adjacent < 0) adjacent += MOD;
  161. }
  162. return adjacent;
  163. }
  164. } // namespace
  165. int main() {
  166. std::ios::sync_with_stdio(false);
  167. std::cin.tie(nullptr);
  168. int edge_count;
  169. std::cin >> original_vertices >> edge_count >> difference_limit;
  170. int capacity = original_vertices + edge_count + 5;
  171. graph.assign(original_vertices + 1, {});
  172. block_cut_tree.assign(capacity, {});
  173. discovery.assign(original_vertices + 1, 0);
  174. low.assign(original_vertices + 1, 0);
  175. for (int id = 0; id < edge_count; ++id) {
  176. int u, v;
  177. std::cin >> u >> v;
  178. graph[u].push_back({v, id});
  179. graph[v].push_back({u, id});
  180. }
  181. total_nodes = original_vertices;
  182. build_block_cut_tree(1, -1);
  183. subtree_size.assign(total_nodes + 1, 0);
  184. maximum_part.assign(total_nodes + 1, 0);
  185. find_original_centroid(1, 0);
  186. rooted_children.assign(total_nodes + 1, {});
  187. order.reserve(total_nodes);
  188. root_tree(centroid, 0);
  189. ways.assign(total_nodes + 1, 0);
  190. std::vector<bool> candidate(original_vertices / 2 + 1, false);
  191. for (int parts = 2; parts <= original_vertices; ++parts) {
  192. int small = original_vertices / parts;
  193. if (small <= original_vertices / 2) candidate[small] = true;
  194. if (original_vertices % parts == 0 && small > 0)
  195. candidate[small - 1] = true;
  196. }
  197. int answer = 0;
  198. for (int size = 1; size <= original_vertices / 2; ++size) {
  199. if (!candidate[size]) continue;
  200. answer += solve_exact_or_adjacent(size, difference_limit);
  201. if (answer >= MOD) answer -= MOD;
  202. }
  203. std::cout << answer << '\n';
  204. return 0;
  205. }