提出 #76708233


ソースコード 拡げる

#include <cstddef>
#include <cstdint>

namespace stew
{
	namespace integer_type
	{
		using u8 = std::uint8_t;
		using u16 = std::uint16_t;
		using u32 = std::uint32_t;
		using u64 = std::uint64_t;
		using i8 = std::int8_t;
		using i16 = std::int16_t;
		using i32 = std::int32_t;
		using i64 = std::int64_t;
		using i128 = __int128;
		using usize = std::size_t;
	}

	using namespace integer_type;
}


#include <concepts>

namespace stew
{
	template<class T>
	struct IOCustom;

	template<class T>
	concept io_custom = requires(const T imut)
	{
		{IOCustom<T>::to_output(imut)} -> std::same_as<void>;
		{IOCustom<T>::from_input()} -> std::convertible_to<T>;
	};
}

#include <concepts>
#include <ranges>
#include <iterator>
#include <iostream>
#include <print>


namespace stew
{
	inline std::istream * in_p = &std::cin;

	// template<class T>
	// struct FromInput;

	struct InStreamPin final
	{
		std::istream * last;

		InStreamPin(std::istream& in) noexcept:
			last{in_p}
		{
			in_p = &in;
		}

		~InStreamPin()
		{
			in_p = last;
		}
	};

	struct IPipeTrait
	{};

	template<class T>
	concept input_pipe = requires(typename T::Element e)
	{
		requires std::derived_from<T, IPipeTrait>;
		{T::pipe(e)} -> std::same_as<void>;
	};

	template<class T>
	inline consteval auto is_normal_inputable() -> bool
	{
		return requires{*in_p >> std::declval<T&>();};
	}

	// template<class T>
	// inline consteval auto is_from_input_inputable() -> bool
	// {
	// 	return requires{FromInput<T>::from_input();};
	// }

	template<class T>
	inline consteval auto is_custom_inputable() -> bool
	{
		return requires{IOCustom<T>::from_input();};
	}

	// 再帰的なので、コンセプト直では無理。関数をかませないといけない
	template<class T>
	inline consteval auto is_inputable() -> bool;

	template<class T>
	inline consteval auto is_input_pipe_inputable() -> bool
	{
		if constexpr(input_pipe<T>)
		{
			return is_inputable<typename T::Element>();
		}
		else return false;
	}

	template<class T>
	inline consteval auto is_range_inputable() -> bool;

	template<class T>
	inline consteval auto is_inputable() -> bool
	{
		return is_normal_inputable<T>() ||
			is_input_pipe_inputable<T>() ||
			// is_from_input_inputable<T>() ||
			is_custom_inputable<T>() ||
			is_range_inputable<T>();
	}

	template<class T>
	inline consteval auto is_range_inputable() -> bool
	{
		if constexpr(std::ranges::range<T>)
		{
			return is_inputable<std::ranges::range_value_t<T>>();
		}
		else return false;
	}

	template<class T>
	concept inputable = is_inputable<T>();

	template<inputable T>
	inline auto input();

	namespace impl
	{
		template<class T>
		using ReturnInputE = decltype(input<T>());
	}

	template<inputable T>
	inline auto input()
	{
		// if constexpr(is_from_input_inputable<T>())
		// {
		// 	return FromInput<T>::from_input();
		// }
		if constexpr(is_input_pipe_inputable<T>())
		{
			auto value = input<typename T::Element>();
			T::pipe(value);
			return value;
		}
		else if constexpr(is_custom_inputable<T>())
		{
			return IOCustom<T>::from_input();
		}
		else if constexpr(is_normal_inputable<T>())
		{
			T value{};
			*in_p >> value;
			return value;
		}
		else
		{
			static_assert([]{return false;}(), "WTF!!?");
		}
	}

	template<class ... Args>
	inline auto inputs() -> std::tuple<impl::ReturnInputE<Args>...>
	{
		return {input<Args>()...};
	}

	// アロケート済み範囲に入力する
	// 型によるアロケート済みでない部分までのガードが必要
	// ex) std::vector<std::vector<NotAllocated<std::tuple<std::vector<int>, int, bool>>>>
	// ガードをネストできない(実行時にサイズが決まる場合など)ため、やり方を変えるべきか。
	// std::vector</* ... */> vec;
	// input_into(vec, SizeTag<"a">(a), SizeTag<"b">(b), SizeTag<"c">(c));
	// みたいな。
	//
	// template<inputable T>
	// inline void input_into_piped_range(impl::ReturnInputE<T>& into_value)
	// {
	// 	if constexpr(is_input_pipe_inputable<T>())
	// 	{
	// 		auto value = input<typename T::Element>();
	// 		T::pipe(value);
	// 		into_value = std::move(value);
	// 	}
	// 	else if constexpr(is_custom_inputable<T>())
	// 	{
	// 		into_value = IOCustom<T>::from_input();
	// 	}
	// 	else if constexpr(is_normal_inputable<T>())
	// 	{
	// 		T value{};
	// 		*in_p >> value;
	// 		into_value = std::move(value);
	// 	}
	// 	else if constexpr(is_range_inputable<T>())
	// 	{
	// 		using E = std::ranges::range_value_t<T>;
	// 		for(auto& e : into_value) e = input<E>();
	// 	}
	// 	else
	// 	{
	// 		static_assert([]{return false;}(), "WTF!!?");
	// 	}
	// }

	// template<inputable T>
	// inline void input_into_range(T& into_value)
	// {
	// 	input_into_piped_range<T>(into_value);
	// }
}

#include <vector>
#include <span>
#include <ranges>
#include <utility>
#include <algorithm>

namespace stew::sparse_matrix {

	template<class E_ = void>
	struct Csr final {
		std::vector<E_> data;
		std::vector<usize> acc_row;
		std::vector<usize> col;

		auto row(const usize index) {
			auto f = [this](const usize i) -> std::pair<usize, E_&> {
				return {this->col[i], this->data[i]};
			};

			if(index >= this->acc_row.size() - 1) {
				return std::views::iota(usize(0), usize(0))
					| std::views::transform(std::move(f));
			}
			else {
				return std::views::iota(this->acc_row[index], this->acc_row[index + 1])
					| std::views::transform(std::move(f));
			}
		}

		auto c_row(const usize index) const {
			auto f = [this](const usize i) -> std::pair<usize, const E_&> {
				return {this->col[i], this->data[i]};
			};

			if(index >= this->acc_row.size() - 1) {
				return std::views::iota(usize(0), usize(0))
					| std::views::transform(std::move(f));
			}
			else {
				return std::views::iota(this->acc_row[index], this->acc_row[index + 1])
					| std::views::transform(std::move(f));
			}
		}

		auto view() {
			return std::views::iota(0u, this->acc_row.size() - 1)
				| std::views::transform([this](const usize i) {
					return this->row(i);
				});
		}

		auto c_view() const {
			return std::views::iota(0u, this->acc_row.size() - 1)
				| std::views::transform([this](const usize i) {
					return this->c_row(i);
				});
		}

		auto begin() {
			return this->view().begin();
		}

		auto end() {
			return this->view().end();
		}

		auto cbegin() const {
			return this->c_view().begin();
		}

		auto cend() const {
			return this->c_view().end();
		}
	};

	template<>
	struct Csr<> final {
		std::vector<usize> acc_row;
		std::vector<usize> col;

		auto row(const usize index) {
			auto f = [this](const usize i) -> usize {
				return this->col[i];
			};

			if(index >= this->acc_row.size() - 1) {
				return std::views::iota(usize(0), usize(0))
					| std::views::transform(std::move(f));
			}
			else {
				return std::views::iota(this->acc_row[index], this->acc_row[index + 1])
					| std::views::transform(std::move(f));
			}
		}

		auto c_row(const usize index) const {
			auto f = [this](const usize i) -> usize {
				return this->col[i];
			};

			if(index >= this->acc_row.size() - 1) {
				return std::views::iota(usize(0), usize(0))
					| std::views::transform(std::move(f));
			}
			else {
				return std::views::iota(this->acc_row[index], this->acc_row[index + 1])
					| std::views::transform(std::move(f));
			}
		}

		auto view() {
			return std::views::iota(0u, this->acc_row.size() - 1)
				| std::views::transform([this](const usize i) {
					return this->row(i);
				});
		}

		auto c_view() const {
			return std::views::iota(0u, this->acc_row.size() - 1)
				| std::views::transform([this](const usize i) {
					return this->c_row(i);
				});
		}

		auto begin() {
			return this->view().begin();
		}

		auto end() {
			return this->view().end();
		}

		auto cbegin() const {
			return this->c_view().begin();
		}

		auto cend() const {
			return this->c_view().end();
		}
	};

	template<class E_ = void>
	struct Coo final {
		std::vector<std::pair<std::pair<usize, usize>, E_>> buffer;
		bool is_sorted = false;

		static auto make(const usize buffer_size) {
			auto buffer = std::vector<std::pair<std::pair<usize, usize>, E_>>{};
			buffer.reserve(buffer_size);
			return Coo<E_> {
				.buffer = std::move(buffer),
				.is_sorted = false
			};
		}

		void add(const std::pair<usize, usize>& index, E_&& elem) {
			this->is_sorted = false;
			this->buffer.emplace_back(std::pair<std::pair<usize, usize>, E_>{index, std::move(elem)});
		}

		void sort() {
			std::ranges::sort(this->buffer);
			this->is_sorted = true;
		}

		auto to_csr(const usize row_size) && -> Csr<E_>
		// [[expect: indices are sorted by row and then by column]]
		{
			if(not this->is_sorted) {
				this->sort();
			}

			std::vector<E_> data{};
			std::vector<usize> acc_row{};
			std::vector<usize> col{};

			data.reserve(this->buffer.size());
			acc_row.reserve(row_size + 1);
			col.reserve(this->buffer.size());

			for(const auto& [index, elem] : this->buffer) {
				data.emplace_back(std::move(elem));
				col.emplace_back(index.second);
			}

			auto it = this->buffer.begin();
			for(usize i = 0; i < row_size; ++i) {
				acc_row.push_back(it - this->buffer.begin());
				while(it != this->buffer.end() && it->first.first == i) {
					++it;
				}
			}
			acc_row.push_back(this->buffer.size());

			return Csr<E_> {
				.data = std::move(data),
				.acc_row = std::move(acc_row),
				.col = std::move(col)
			};
		}
	};

	template<>
	struct Coo<> final {
		std::vector<std::pair<usize, usize>> buffer;
		bool is_sorted = false;

		static auto make(const usize buffer_size) {
			auto buffer = std::vector<std::pair<usize, usize>>{};
			buffer.reserve(buffer_size);
			return Coo<> {
				.buffer = std::move(buffer),
				.is_sorted = false
			};
		}

		void add(const std::pair<usize, usize>& index) {
			this->is_sorted = false;
			this->buffer.push_back(index);
		}

		void sort() {
			std::ranges::sort(this->buffer);
			this->is_sorted = true;
		}

		auto to_csr(const usize row_size) && -> Csr<> {
			if(not this->is_sorted) {
				this->sort();
			}

			std::vector<usize> acc_row{};
			std::vector<usize> col{};

			acc_row.reserve(row_size + 1);
			col.reserve(this->buffer.size());

			for(const auto& index : this->buffer) {
				col.push_back(index.second);
			}

			auto it = this->buffer.begin();
			for(usize i = 0; i < row_size; ++i) {
				acc_row.push_back(it - this->buffer.begin());
				while(it != this->buffer.end() && it->first == i) {
					++it;
				}
			}
			acc_row.push_back(this->buffer.size());

			return Csr<> {
				.acc_row = std::move(acc_row),
				.col = std::move(col)
			};
		}
	};
}


#include <cstddef>
#include <utility>
#include <vector>
#include <optional>

namespace stew {

	template<class T_ = void>
	struct UnionFind final {
		std::vector<usize> root;
		std::vector<usize> size;
		std::vector<T_> data;

		constexpr UnionFind(std::vector<T_>&& data) noexcept
		: root(data.size())
		, size(data.size(), 1)
		, data(std::move(data))
		{
			for(usize i = 0; i < this->data.size(); ++i) {
				this->root[i] = i;
			}
		}

		constexpr auto get(const usize x) const noexcept -> const T_& {
			return this->data[this->find(x)];
		}

		constexpr auto get(const usize x) noexcept -> T_& {
			return this->data[this->find(x)];
		}

		constexpr auto find(const usize x) noexcept -> usize {
			if(this->root[x] == x) {
				return x;
			} else {
				return this->root[x] = this->find(this->root[x]);
			}
		}

		constexpr auto unite(usize x, usize y, auto&& f, bool call_when_same) noexcept -> std::optional<usize>
		requires requires(T_ vx, T_ vy, bool is_x) {
			{f(vx, vy, is_x)} -> std::same_as<T_>;
		} {
			x = this->find(x);
			y = this->find(y);
			if(x == y) {
				if(call_when_same) {
					this->data[x] = f(this->data[x], this->data[y], true);
				}
				return std::nullopt;
			}
			bool is_x = true;
			if(this->size[x] < this->size[y]) {
				std::swap(x, y);
				is_x = false;
			}
			this->root[y] = x;
			this->size[x] += this->size[y];
			this->data[x] = f(this->data[x], this->data[y], is_x);
			return x;
		}
	};

	template<>
	struct UnionFind<void> final {
		std::vector<usize> root;
		std::vector<usize> size;

		constexpr UnionFind(const usize n) noexcept
		: root(n)
		, size(n, 1)
		{
			for(usize i = 0; i < n; ++i) {
				this->root[i] = i;
			}
		}

		constexpr auto find(const usize x) noexcept -> usize {
			if(this->root[x] == x) {
				return x;
			} else {
				return this->root[x] = this->find(this->root[x]);
			}
		}

		constexpr auto unite(usize x, usize y) noexcept -> std::optional<usize> {
			x = this->find(x);
			y = this->find(y);
			if(x == y) {
				return std::nullopt;
			}
			if(this->size[x] < this->size[y]) std::swap(x, y);
			this->root[y] = x;
			this->size[x] += this->size[y];
			return x;
		}
	};
}

namespace stew::i_pipes
{
	template<class T>
	requires std::integral<T>
	struct Decrementer final : IPipeTrait
	{
		using Element = T;

		static auto pipe(T& mut) -> void
		{
			--mut;
		}
	};
}

namespace stew {
	template<class T>
	using D = i_pipes::Decrementer<T>;
}

#include <unordered_set>
#include <set>
#include <unordered_map>
#include <list>
#include <map>
#include <queue>

#include <concepts>
#include <utility>

namespace stew::binary_search {
	template<class T_, class MiddleF_ = decltype([]<class Int_> requires std::integral<Int_> (const Int_& l, const Int_& r){return (l + r) / 2;})>
	inline auto binary_search(const T_& left, const T_& right, const auto& pred, const bool left_is, const MiddleF_& middle = {}) -> std::pair<T_, T_> requires
		requires(const T_ v) {
			{pred(v)} -> std::convertible_to<bool>;
			{middle(left, right)} -> std::convertible_to<T_>;
		}
	{
		T_ l = left;
		T_ r = right;
		while(r - l > 1) {
			const T_ mid = middle(l, r);
			if(pred(mid) ^ left_is) {
				r = mid;
			} else {
				l = mid;
			}
		}
		return {l, r};
	}
}


#include <concepts>
#include <type_traits>
namespace stew {
	template<class T_, class U_>
	concept univ_ref = std::same_as<std::remove_cvref_t<T_>, U_>;
}


#include <concepts>

namespace stew::monoid
{
	template<class T_>
	struct Monoid {
		static_assert([]{return false;}(), "No Monoid defined for this type");
	};

	template<class T_>
	concept monoid = requires(const T_ imut1, const T_ imut2)
	{
		{Monoid<T_>::op(imut1, imut2)} -> std::same_as<T_>;
		{Monoid<T_>::ide()} -> std::same_as<T_>;
	};
}


#include <cstddef>
#include <stdexcept>
#include <vector>


namespace stew::swag::impl {
	using monoid::Monoid;

	template<monoid::monoid T_>
	struct Swag final {
		using M = Monoid<T_>;

		std::vector<std::pair<T_, T_>> back{{M::ide(), M::ide()}};
		std::vector<std::pair<T_, T_>> front{{M::ide(), M::ide()}};
		std::vector<T_> buf{};

		constexpr void push_back(univ_ref<T_> auto&& x_) {
			T_ x{std::forward<decltype(x_)>(x_)};

			const auto& [_, acc_] = this->back.back();
			T_ acc = M::op(acc_, x);
			this->back.emplace_back(std::move(x), std::move(acc));
		}

		constexpr void push_front(univ_ref<T_> auto&& x_) {
			T_ x{std::forward<decltype(x_)>(x_)};

			const auto& [_, acc_] = this->front.back();
			T_ acc = M::op(x, acc_);
			this->front.emplace_back(std::move(x), std::move(acc));
		}

		constexpr auto pop_back() noexcept -> T_ {
			if(this->back.size() == 1 && this->front.size() == 1) {
				throw std::runtime_error{"panic! pop_back from empty swag."};
			}

			if(this->back.size() == 1) {
				const usize k = this->front.size() - 1;
				const usize moved = (k - 1) / 2;
				const usize stay = k - 1 - moved;

				// 先頭~約半分をbufに退避
				this->buf.clear();
				for(usize i = 0; i < stay; ++i) {
					auto x = std::move(this->front.back().first);
					this->buf.emplace_back(std::move(x));
					this->front.pop_back();
				}

				// 約半分~末尾-1をbackに追加
				for(usize i = 0; i < moved; ++i) {
					auto x = std::move(this->front.back().first);
					this->push_back(std::move(x));
					this->front.pop_back();
				}

				// 末尾をpop
				auto ret = std::move(this->front.back().first);
				this->front.pop_back();

				// bufの退避を戻す
				for(usize i = 0; i < stay; ++i) {
					this->push_front(std::move(this->buf.back()));
					this->buf.pop_back();
				}

				this->buf.clear();
				return ret;
			}
			else {
				auto ret = std::move(this->back.back().first);
				this->back.pop_back();
				return ret;
			}
		}

		constexpr auto pop_front() noexcept -> T_ {
			if(this->back.size() == 1 && this->front.size() == 1) {
				throw std::runtime_error{"panic! pop_front from empty swag."};
			}
			
			if(this->front.size() == 1) {
				const usize k = this->back.size() - 1;
				const usize moved = (k - 1) / 2;
				const usize stay = k - 1 - moved;

				// 末尾~約半分をbufに退避
				this->buf.clear();
				for(usize i = 0; i < stay; ++i) {
					auto x = std::move(this->back.back().first);
					this->buf.emplace_back(std::move(x));
					this->back.pop_back();
				}

				// 約半分~先頭-1をfrontに追加
				for(usize i = 0; i < moved; ++i) {
					auto x = std::move(this->back.back().first);
					this->push_front(std::move(x));
					this->back.pop_back();
				}

				// 先頭をpop
				auto ret = std::move(this->back.back().first);
				this->back.pop_back();

				// bufの退避を戻す
				for(usize i = 0; i < stay; ++i) {
					this->push_back(std::move(this->buf.back()));
					this->buf.pop_back();
				}

				this->buf.clear();
				return ret;
			}
			else {
				auto ret = std::move(this->front.back().first);
				this->front.pop_back();
				return ret;
			}
		}

		constexpr auto fold() const noexcept -> T_ {
			return M::op(this->front.back().second, this->back.back().second);
		}
	};
}


#include <algorithm>
#include <concepts>
#include <type_traits>
#include <utility>
#include <vector>

namespace stew::shakutori {
	// 内部可変性で外側にはimutableなものに`mutable`を使うのがちょっと不安なので、
	// 本来constであるべきものをconstにせず制約づけてる
	// 内部可変性のメンタルモデルがあんまりない...

	// noexceptも同様に無視してる

	// ビバ償却定数!

	template<class T_>
	concept slide_window = requires(T_& mut) {
		typename T_::Element;
		typename T_::Ret;
		requires requires (const T_::Element& e) {
			{mut.extend_r(e)};
			{mut.shrink_l(e)};
			{mut.value()} -> std::convertible_to<typename T_::Ret>;
		};
	};

	template<class T_>
	concept tryable_slide_window = slide_window<T_> && requires(const T_::Element& e, T_& mut) {
		{mut.shrink_r(e)};
	};

	// ほんとはstd::generatorで書くべきかも
	template<class Ret_, bool is_true_continue, class Idx_>
	inline constexpr auto shak_window(auto& prop, auto& range_to_val, auto& arr, const std::pair<Idx_, Idx_>& haop) noexcept -> std::vector<Ret_>
	requires
		(tryable_slide_window<std::remove_cvref_t<decltype(prop)>> && std::convertible_to<typename std::remove_cvref_t<decltype(prop)>::Ret, bool>)
		&& (slide_window<std::remove_cvref_t<decltype(range_to_val)>> && std::convertible_to<typename std::remove_cvref_t<decltype(range_to_val)>::Ret, Ret_>)
		&& (std::same_as<std::remove_cvref_t<decltype(arr(std::declval<Idx_>()))>, typename std::remove_cvref_t<decltype(prop)>::Element> && std::same_as<typename std::remove_cvref_t<decltype(prop)>::Element, typename std::remove_cvref_t<decltype(range_to_val)>::Element>)
	{
		const auto& [bi, en] = haop;
		std::vector<Ret_> ret{};
		Idx_ r = bi;

		for(Idx_ l = bi; l < en; ++l) {
			r = std::max<Idx_>(l, r);

			while(r < en) {
				prop.extend_r(arr(r));

				const bool prop_val = prop.value();
				if(prop_val == is_true_continue) {
					range_to_val.extend_r(arr(r));
					++r;
				}
				else {
					prop.shrink_r(arr(r));
					break;
				}
			}

			ret.emplace_back(range_to_val.value());
			if(l != r) {
				prop.shrink_l(arr(l));
				range_to_val.shrink_l(arr(l));
			}
		}

		return ret;
	}

	// std::generatorで書きたいかも
	template<bool is_true_continue, class Idx_>
	inline constexpr auto shak(auto& prop, const std::pair<Idx_, Idx_>& haop) noexcept -> std::vector<std::pair<Idx_, Idx_>>
	requires requires(const Idx_& l, const Idx_& r) {
		{prop(l, r)} -> std::convertible_to<bool>;
	} {
		const auto& [bi, en] = haop;
		std::vector<std::pair<Idx_, Idx_>> ret{};
		Idx_ r = bi;

		for(Idx_ l = bi; l < en; ++l) {
			r = std::max<Idx_>(l, r);

			while(r < en) {
				const bool prop_val = prop(l, r + 1);
				if(prop_val == is_true_continue) {
					++r;
				}
				else {
					break;
				}
			}

			ret.emplace_back(l, r);
		}

		return ret;
	}
}
using namespace stew;


int main() {
	std::array<std::array<i64, 6>, 3> dices{};
	for(i64 id = 0; id < 3; ++id) {
		for(i64 im = 0; im < 6; ++im) {
			dices[id][im] = input<i64>();
		}
	}

	i64 ans = 0;
	for(i64 i1 = 0; i1 < 6; ++i1) {
		for(i64 i2 = 0; i2 < 6; ++i2) {
			for(i64 i3 = 0; i3 < 6; ++i3) {
				if(std::set{dices[0][i1], dices[1][i2], dices[2][i3]} == std::set<i64>{4, 5, 6}) {
					++ans;
				}
			}
		}
	}
	std::println("{:.20}", (long double)(ans) / 216);
}

提出情報

提出日時
問題 D - 456
ユーザ Klow
言語 C++23 (GCC 15.2.0)
得点 200
コード長 21868 Byte
結果 AC
実行時間 13 ms
メモリ 6764 KiB

ジャッジ結果

セット名 Sample All
得点 / 配点 0 / 0 200 / 200
結果
AC × 2
AC × 14
セット名 テストケース
Sample sample_01.txt, sample_02.txt
All random_01.txt, random_02.txt, random_03.txt, random_04.txt, random_05.txt, random_06.txt, random_07.txt, random_08.txt, random_09.txt, random_10.txt, random_11.txt, random_12.txt, sample_01.txt, sample_02.txt
ケース名 結果 実行時間 メモリ
random_01.txt AC 13 ms 6564 KiB
random_02.txt AC 2 ms 6716 KiB
random_03.txt AC 2 ms 6552 KiB
random_04.txt AC 2 ms 6764 KiB
random_05.txt AC 2 ms 6552 KiB
random_06.txt AC 2 ms 6712 KiB
random_07.txt AC 2 ms 6704 KiB
random_08.txt AC 2 ms 6712 KiB
random_09.txt AC 2 ms 6660 KiB
random_10.txt AC 2 ms 6712 KiB
random_11.txt AC 2 ms 6552 KiB
random_12.txt AC 2 ms 6456 KiB
sample_01.txt AC 2 ms 6736 KiB
sample_02.txt AC 2 ms 6660 KiB