Guest User

Untitled

a guest
May 20th, 2018
115
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.78 KB | None | 0 0
  1. #include <cstdint>
  2. #include <cstdlib>
  3. #include <type_traits>
  4. #include <utility>
  5. #include <memory>
  6. #include <range/v3/core.hpp>
  7. #include <range/v3/span.hpp>
  8. #include <range/v3/action/insert.hpp>
  9. #include <range/v3/numeric/accumulate.hpp>
  10. #include <range/v3/utility/functional.hpp>
  11. #include <range/v3/view/indices.hpp>
  12. #include <range/v3/view/sliding.hpp>
  13. #include <range/v3/view/transform.hpp>
  14. #include <boost/container/flat_map.hpp>
  15. #include <boost/container/static_vector.hpp>
  16. #include <boost/hof/construct.hpp>
  17. #include <boost/hof/unpack.hpp>
  18.  
  19. // HACK: make flat_map play nice with span until it gains its own proper data() member;
  20. // unnecessary some point post-Boost 1.67
  21. namespace boost::container {
  22. template<typename... Ts>
  23. typename flat_map<Ts...>::pointer data(flat_map<Ts...>& fm) noexcept {
  24. return !fm.empty() ? std::addressof(*fm.begin()) : nullptr;
  25. }
  26.  
  27. template<typename... Ts>
  28. typename flat_map<Ts...>::const_pointer data(flat_map<Ts...> const& fm) noexcept {
  29. return !fm.empty() ? std::addressof(*fm.begin()) : nullptr;
  30. }
  31. }
  32.  
  33. namespace hof = boost::hof;
  34. namespace rngs = ranges;
  35. namespace rngvs = rngs::view;
  36.  
  37. using int_t = std::int_fast8_t;
  38. using distance_t = std::int_fast16_t;
  39.  
  40. namespace detail {
  41. using indexed_ints_t = boost::container::flat_map<
  42. distance_t, int_t, // <n: int_t, idx: size_t> -- representational optimization
  43. rngs::less,
  44. boost::container::static_vector<std::pair<distance_t, int_t>, 100>
  45. >;
  46.  
  47. auto const index_ints = [](auto const& ints) -> indexed_ints_t {
  48. indexed_ints_t ret;
  49. rngs::action::insert(
  50. ret,
  51. rngvs::transform(ints, rngvs::indices(static_cast<int_t>(rngs::size(ints))),
  52. hof::construct<indexed_ints_t::value_type>())
  53. );
  54. return ret;
  55. };
  56.  
  57. auto const sum_consecutive_distances = [](rngs::span<indexed_ints_t::value_type const> const indexed_ints) -> distance_t {
  58. return rngs::accumulate(
  59. rngvs::sliding(indexed_ints, 2),
  60. distance_t{}, rngs::plus{},
  61. [](auto const& iis) {
  62. auto [a, a_idx] = iis.front();
  63. auto const& [b, b_idx] = iis.back();
  64. return ++a == b ? static_cast<int_t>(std::abs(b_idx - a_idx)) : int_t{}; // ++ avoids promotion
  65. }
  66. );
  67. };
  68.  
  69. auto const sum_gapped_distances = [](distance_t const gap, indexed_ints_t const& indexed_ints) -> distance_t {
  70. return rngs::accumulate(
  71. rngs::span{indexed_ints},
  72. distance_t{}, rngs::plus{},
  73. hof::unpack([&indexed_ints, gap](auto n, auto const idx) {
  74. auto const it = indexed_ints.find(n += gap); // += avoids promotion
  75. return it != indexed_ints.end() ? static_cast<int_t>(std::abs(it->second - idx)) : int_t{};
  76. })
  77. );
  78. };
  79. } // namespace detail
  80.  
  81. auto const sum_distances = [](int_t const gap, auto const& ints)
  82. -> std::enable_if_t<std::is_same_v<rngs::range_value_type_t<decltype(ints)>, int_t>, distance_t>
  83. {
  84. auto const indexed_ints = detail::index_ints(ints);
  85. return gap == int_t{1}
  86. ? detail::sum_consecutive_distances(indexed_ints)
  87. : detail::sum_gapped_distances(gap, indexed_ints);
  88. };
  89.  
  90. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  91. // demo
  92.  
  93. #include <cstddef>
  94. #include <exception>
  95. #include <bitset>
  96. #include <optional>
  97. #include <string_view>
  98. #include <tuple>
  99. #include <string>
  100. #include <iostream>
  101. #include <range/v3/algorithm/all_of.hpp>
  102. #include <range/v3/algorithm/copy.hpp>
  103. #include <range/v3/algorithm/for_each.hpp>
  104. #include <range/v3/view/generate.hpp>
  105. #include <range/v3/view/generate_n.hpp>
  106. #include <range/v3/view/take_while.hpp>
  107. #include <boost/fusion/include/std_tuple.hpp>
  108. #include <boost/hof/capture.hpp>
  109. #include <boost/hof/flow.hpp>
  110. #include <boost/hof/rotate.hpp>
  111. #include <boost/spirit/home/x3/core.hpp>
  112. #include <boost/spirit/home/x3/auxiliary/attr.hpp>
  113. #include <boost/spirit/home/x3/auxiliary/eoi.hpp>
  114. #include <boost/spirit/home/x3/char/char_class.hpp>
  115. #include <boost/spirit/home/x3/directive/repeat.hpp>
  116. #include <boost/spirit/home/x3/numeric/int.hpp>
  117. #include <boost/spirit/home/x3/numeric/uint.hpp>
  118. #include <boost/spirit/home/x3/operator/alternative.hpp>
  119. #include <boost/spirit/home/x3/operator/sequence.hpp>
  120.  
  121. namespace x3 = boost::spirit::x3;
  122.  
  123. using header = std::tuple<std::size_t, int_t, int_t>; // <rows, cols, gap>
  124.  
  125. namespace {
  126.  
  127. template<int_t N>
  128. std::integral_constant<int_t, N> constexpr int_c{};
  129.  
  130. x3::int_parser<int_t> constexpr int_parser{};
  131. x3::uint_parser<std::size_t> constexpr rows_parser{};
  132.  
  133. struct failfast { };
  134.  
  135. auto const make_line_parser = [](std::string_view const line, auto&& parser) {
  136. return [line, parser = decltype(parser)(parser)](auto& attr) -> bool {
  137. return x3::phrase_parse(line.begin(), line.end(), parser >> x3::eoi, x3::ascii::space, attr);
  138. };
  139. };
  140.  
  141. auto const parse_header = [](std::string_view const line) -> std::optional<header> {
  142. auto const parse_into = make_line_parser(line, rows_parser >> int_parser >> (int_parser | x3::attr(int_c<1>)));
  143. auto constexpr are_in_range = hof::unpack([](auto const rows, auto const cols, auto const gap) noexcept {
  144. return rows && cols > int_t{} && cols <= int_t{100} && gap > int_t{} && gap < int_t{100};
  145. });
  146.  
  147. std::optional<header> ret;
  148. if (!line.empty() && (!parse_into(ret.emplace()) || !are_in_range(*ret))) {
  149. ret = std::nullopt;
  150. }
  151. return ret;
  152. };
  153.  
  154. auto const parse_ints = [](int_t const count, std::string_view const line) -> boost::container::static_vector<int_t, 100> {
  155. auto const parse_into = make_line_parser(line, x3::repeat(count)[int_parser]);
  156. auto constexpr are_in_range = hof::capture([](auto const n) noexcept { return n > int_t{} && n <= int_t{100}; })
  157. (hof::rotate(rngs::all_of));
  158. auto const are_unique = [](auto const& ints) {
  159. std::bitset<100> ints_set;
  160. return rngs::all_of(
  161. ints,
  162. [&ints_set](auto const i) noexcept -> bool { return ints_set[i].flip(); },
  163. [](std::make_unsigned_t<int_t> n) noexcept -> std::size_t { return --n; }
  164. );
  165. };
  166.  
  167. boost::container::static_vector<int_t, 100> ret;
  168. if (line.empty() || !parse_into(ret)) {
  169. throw failfast{};
  170. }
  171. if (rngs::span const rsp{std::as_const(ret)}; !are_in_range(rsp) || !are_unique(rsp)) {
  172. throw failfast{};
  173. }
  174. return ret;
  175. };
  176.  
  177. void impl()
  178. try {
  179. std::string line_buf_;
  180. line_buf_.reserve(291); // max for trim valid input: characters in stringized [1,100] + delimiting spaces
  181. auto const read_line = [&line_buf_]() -> std::string_view {
  182. if (!std::getline(std::cin, line_buf_)) {
  183. throw failfast{};
  184. }
  185. return line_buf_;
  186. };
  187. auto read_print_distances = hof::unpack([read_line](auto const rows, auto const cols, auto const gap) {
  188. rngs::copy(
  189. rngvs::generate_n(hof::flow(read_line,
  190. hof::capture(cols)(parse_ints),
  191. hof::construct<rngs::span<int_t const>>(),
  192. hof::capture(gap)(sum_distances)),
  193. rows),
  194. rngs::ostream_iterator{std::cout, "\n"}
  195. );
  196. });
  197.  
  198. rngs::for_each(
  199. rngvs::generate(hof::flow(read_line, parse_header)) | rngvs::take_while(rngs::convert_to<bool>{}),
  200. rngs::indirect(std::move(read_print_distances))
  201. );
  202. } catch (failfast) { }
  203.  
  204. } // anon namespace
  205.  
  206. int main()
  207. try {
  208. std::ios::sync_with_stdio(false);
  209. impl();
  210. return EXIT_SUCCESS;
  211. } catch (std::exception const& ex) {
  212. std::cerr << ex.what() << '\n';
  213. return EXIT_FAILURE;
  214. } catch (...) {
  215. std::cerr << "unknown exception (...)\n";
  216. return EXIT_FAILURE;
  217. }
Add Comment
Please, Sign In to add comment