#ifndef INCLUDE_MODE #define INCLUDE_MODE // #define REACTIVE // #define USE_GETLINE #endif #ifdef INCLUDE_MAIN inline void Solve() { // 入力受け取りとグラフの構築 // (実装は好きにして良いが全ての辺を前計算してメモリ上に置くと重くなることに注意) H = W = 1e3; H_minus = H - 1; W_minus = W - 1; HW = H * W; CEXPR( int , bound_N , 2e5 ); CIN_ASSERT( N , 1 , bound_N ); vector xy( N ); FOR( i , 0 , N ){ CIN_ASSERT( xi , 0 , W_minus ); CIN_ASSERT( yi , 0 , H_minus ); xy[i] = EnumHW_inv( {yi,xi} ); } CEXPR( int , bound_M , 2e5 ); CIN_ASSERT( M , 1 , bound_M ); vector zw( HW ); FOR( j , 0 , M ){ CIN_ASSERT( zj , 0 , W_minus ); CIN_ASSERT( wj , 0 , H_minus ); zw[EnumHW_inv( {wj,zj} )] = true; } string S = ""; REPEAT( W ){ S += "."; } wall_str.resize( H , S ); auto edge = [&]( const int& v ){ vector answer{}; if( v < HW ){ answer = EdgeOnGrid( v ); if( zw[v] ){ answer.push_back( HW + 1 ); } } else if ( v == HW ){ answer = xy; } return answer; }; Graph graph{ HW + 2 , edge }; // 幅優先探索で距離を計算(実装は好きにして良い) BreadthFirstSearch bfs{ graph , -1 , HW }; auto d = bfs.GetDistance(); // 答えの出力 RETURN( d[HW+1] - 2 ); } REPEAT_MAIN(1); #else // INCLUDE_MAIN #ifdef INCLUDE_LIBRARY // https://github.com/p-adic/cpp // VVV ライブラリは以下に挿入する。 class is_ordered { private: is_ordered() = delete; template static constexpr auto Check( const T& t ) -> decltype( t < t , true_type() ); static constexpr false_type Check( ... ); public: template static constexpr const bool value = is_same_v< decltype( Check( declval() ) ) , true_type >; }; template typename T> struct hash> : public hash { inline size_t operator()( const T& n ) const; }; template using Map = conditional_t>,unordered_map,conditional_t,map,void>>; // Mapは // - unordered_map()がwell-formedならばunordered_map // - そうでなくoperator<(declval(),declval())がwell-formedならばmap // - そうでないならばvoid template typename T> inline size_t hash>::operator()( const T& n ) const { return hash::operator()( n.Represent() ); } #define DECLARATION_OF_CPOINT( POINT ) inline const U& POINT() const noexcept #define DECLARATION_OF_POINT( POINT ) inline U& POINT() noexcept #define DEFINITION_OF_CPOINT( POINT ) template inline const U& VirtualPointedSet::POINT() const noexcept { return Point(); } #define DEFINITION_OF_POINT( POINT ) template inline U& VirtualPointedSet::POINT() noexcept { return Point(); } // - インタフェースをなるべく抽象型で与えて仮想継承する。 // - 具体的構造が2種類以上あるものはもちろん抽象型を仮想継承する。 // - VirtualPointedSetのように具体的構造が1種類しかないものも仮想継承のコンストラクタ呼び出しを // 省略するためになるべく抽象型を用意する。 // - AbstractDijkstraのように全ての具体的構造が1つの具体的構造の派生である場合は // インタフェースを必要としない。 // - コンストラクタはなるべく省略できるようにするが、ポインタはメンバ変数にしない。 // - VirtualGraphのように具体的構造が2種類以上あるもので全てに共通の定義本体を持つ関数(Edge)が // 必要な場合は実装が膨れ上がらないように抽象型に関数の定義をし、そのため抽象型にメンバ変数が // 必要になる場合はコンストラクタを非自明なものにする // - 代わりにポインタを抽象型のメンバとして // 派生クラスのコンストラクタの定義内でアドレスを渡すようにすると、ムーブなどで意図せず // ポインタの指すアドレスが意図通りでなくなることに注意する。 // - データ構造に渡すことを想定する。 // - データ構造の配列や初期化をムーブセマンティクスで処理できるようにするために // 代数構造もムーブコンストラクタがdeleteされないようにする。 // - そのために演算に対応する関数オブジェクトは参照ではなく実体としてメンバに持つ。 template class UnderlyingSet { public: using type = U; }; template class VirtualPointedSet : virtual public UnderlyingSet { public: virtual const U& Point() const noexcept = 0; virtual U& Point() noexcept = 0; DECLARATION_OF_CPOINT( Unit ); DECLARATION_OF_CPOINT( Zero ); DECLARATION_OF_CPOINT( One ); DECLARATION_OF_CPOINT( Infty ); DECLARATION_OF_POINT( init ); DECLARATION_OF_POINT( root ); }; template class PointedSet : virtual public VirtualPointedSet { private: U m_b_U; public: inline PointedSet( const U& b_u = U() ); inline const U& Point() const noexcept; inline U& Point() noexcept; }; template class VirtualNSet : virtual public UnderlyingSet { public: virtual U Transfer( const U& u ) = 0; inline U Inverse( const U& u ); }; template class AbstractNSet : virtual public VirtualNSet { private: F_U m_f_U; public: inline AbstractNSet( F_U f_U ); inline U Transfer( const U& u ); }; template class VirtualMagma : virtual public UnderlyingSet { public: virtual U Product( const U& u0 , const U& u1 ) = 0; inline U Sum( const U& u0 , const U& u1 ); }; template class AdditiveMagma : virtual public VirtualMagma { public: inline U Product( const U& u0 , const U& u1 ); }; template class MultiplicativeMagma : virtual public VirtualMagma { public: inline U Product( const U& u0 , const U& u1 ); }; template class AbstractMagma : virtual public VirtualMagma { private: M_U m_m_U; public: inline AbstractMagma( M_U m_U ); inline U Product( const U& u0 , const U& u1 ); }; template inline PointedSet::PointedSet( const U& b_U ) : m_b_U( b_U ) {} template inline const U& PointedSet::Point() const noexcept { return m_b_U; } template inline U& PointedSet::Point() noexcept { return m_b_U; } DEFINITION_OF_CPOINT( Unit ); DEFINITION_OF_CPOINT( Zero ); DEFINITION_OF_CPOINT( One ); DEFINITION_OF_CPOINT( Infty ); DEFINITION_OF_POINT( init ); DEFINITION_OF_POINT( root ); template inline AbstractNSet::AbstractNSet( F_U f_U ) : m_f_U( move( f_U ) ) { static_assert( is_invocable_r_v ); } template inline U AbstractNSet::Transfer( const U& u ) { return m_f_U( u ); } template inline U VirtualNSet::Inverse( const U& u ) { return Transfer( u ); } template inline AbstractMagma::AbstractMagma( M_U m_U ) : m_m_U( move( m_U ) ) { static_assert( is_invocable_r_v ); } template inline U AdditiveMagma::Product( const U& u0 , const U& u1 ) { return u0 + u1; } template inline U MultiplicativeMagma::Product( const U& u0 , const U& u1 ) { return u0 * u1; } template inline U AbstractMagma::Product( const U& u0 , const U& u1 ) { return m_m_U( u0 , u1 ); } template inline U VirtualMagma::Sum( const U& u0 , const U& u1 ) { return Product( u0 , u1 ); } // グラフ用 #ifndef RET_TYPE #define RET_TYPE template using ret_t = decltype( declval()( declval()... ) ); #endif #ifndef INNER_TYPE #define INNER_TYPE template using inner_t = typename T::type; #endif // Enumeration:N->R1-->TとEnumeration_inv:T->R2-->Nは互いに逆写像である仮想関数。 template class VirtualGraph : virtual public UnderlyingSet { public: virtual R1 Enumeration( const int& i ) = 0; inline R2 Enumeration_inv( const T& t ); template inline R2 Enumeration_inv( const PATH& p ); inline void Reset(); virtual const int& size() const noexcept = 0; virtual E& edge() noexcept = 0; virtual ret_t Edge( const T& t ) = 0; private: virtual inline R2 Enumeration_inv_Body( const T& t ) = 0; }; template class EdgeImplimentation : virtual public VirtualGraph { private: int m_size; // 配列への参照を返す関数オブジェクトを構築して返す関数の返り値などの右辺値を受け取ることを // 許容したいので左辺値参照にはしない。 E m_edge; public: inline EdgeImplimentation( const int& size , E edge ); inline const int& size() const noexcept; inline E& edge() noexcept; inline ret_t Edge( const T& t ); }; template class Graph : public EdgeImplimentation { public: inline Graph( const int& size , E edge ); inline const int& Enumeration( const int& i ); template inline Graph GetGraph( F edge ) const; private: inline const int& Enumeration_inv_Body( const int& t ); }; template class EnumerationGraph : public EdgeImplimentation,ret_t,E> { private: Enum_T m_enum_T; Enum_T_inv m_enum_T_inv; public: inline EnumerationGraph( const int& size , Enum_T enum_T , Enum_T_inv enum_T_inv , E edge ); inline ret_t Enumeration( const int& i ); template inline EnumerationGraph GetGraph( F edge ) const; private: inline ret_t Enumeration_inv_Body( const T& t ); }; template EnumerationGraph( const int& size , Enum_T enum_T , Enum_T_inv enum_T_inv , E edge ) -> EnumerationGraph()(0)),Enum_T,Enum_T_inv,E>; // 推論補助のためにE::operator()はデフォルト引数が必要。 template class MemorisationGraph : public EdgeImplimentation { private: int m_length; vector m_memory; Map m_memory_inv; public: inline MemorisationGraph( const int& size , E edge ); // push_backする可能性のあるvectorなので参照にしないように注意 inline T Enumeration( const int& i ); inline void Reset(); template inline MemorisationGraph GetGraph( F edge ) const; private: inline const int& Enumeration_inv_Body( const T& t ); }; template MemorisationGraph( const int& size , E edge ) -> MemorisationGraph()().back()),E>; template MemorisationGraph( const int& size , E edge ) -> MemorisationGraph(declval()().back())),E>; template inline EdgeImplimentation::EdgeImplimentation( const int& size , E edge ) : m_size( size ) , m_edge( move( edge ) ) { static_assert( is_constructible_v && is_constructible_v && is_invocable_v ); } template inline Graph::Graph( const int& size , E edge ) : EdgeImplimentation( size , move( edge ) ) {} template inline EnumerationGraph::EnumerationGraph( const int& size , Enum_T enum_T , Enum_T_inv enum_T_inv , E edge ) : EdgeImplimentation,ret_t,E>( size , move( edge ) ) , m_enum_T( move( enum_T ) ) , m_enum_T_inv( move( enum_T_inv ) ) {} template inline MemorisationGraph::MemorisationGraph( const int& size , E edge ) : EdgeImplimentation( size , move( edge ) ) , m_length() , m_memory() , m_memory_inv() { static_assert( is_invocable_v && is_invocable_v ); } template inline const int& Graph::Enumeration( const int& i ) { return i; } template inline ret_t EnumerationGraph::Enumeration( const int& i ) { return m_enum_T( i ); } template inline T MemorisationGraph::Enumeration( const int& i ) { assert( 0 <= i && i < m_length ); return m_memory[i]; } template inline R2 VirtualGraph::Enumeration_inv( const T& t ) { return Enumeration_inv_Body( t ); } template template inline R2 VirtualGraph::Enumeration_inv( const PATH& p ) { return Enumeration_inv_Body( get<0>( p ) ); } template inline const int& Graph::Enumeration_inv_Body( const int& i ) { return i; } template inline ret_t EnumerationGraph::Enumeration_inv_Body( const T& t ) { return m_enum_T_inv( t ); } template inline const int& MemorisationGraph::Enumeration_inv_Body( const T& t ) { if( m_memory_inv.count( t ) == 0 ){ assert( m_length < this->size() ); m_memory.push_back( t ); return m_memory_inv[t] = m_length++; } return m_memory_inv[t]; } template void VirtualGraph::Reset() {} template inline void MemorisationGraph::Reset() { m_length = 0; m_memory.clear(); m_memory_inv.clear(); } template inline const int& EdgeImplimentation::size() const noexcept { return m_size; } template inline E& EdgeImplimentation::edge() noexcept { return m_edge; } template inline ret_t EdgeImplimentation::Edge( const T& t ) { return m_edge( t ); } template template inline Graph Graph::GetGraph( F edge ) const { return Graph( this->size() , move( edge ) ); } template template inline EnumerationGraph EnumerationGraph::GetGraph( F edge ) const { return EnumerationGraph( this->size() , m_enum_T , m_enum_T_inv , move( edge ) ); } template template inline MemorisationGraph MemorisationGraph::GetGraph( F edge ) const { return MemorisationGraph( this->size() , move( edge ) ); } template typename V> inline auto Get( const V& a ) { return [&]( const int& i = 0 ){ return a[i]; }; } // グリッド問題用 int H , W , H_minus , W_minus , HW; vector wall_str; char walkable = '.' , unwalkable = '#'; inline T2 EnumHW( const int& v ) { return { v / W , v % W }; } inline int EnumHW_inv( const T2& ij ) { auto& [i,j] = ij; return i * W + j; } inline vector EdgeOnGrid( const int& v ){vectoranswer{};auto[i,j]=EnumHW(v);if(i>0&&wall_str[i-1][j]==walkable){answer.push_back(EnumHW_inv({i-1,j}));}if(i+10&&wall_str[i][j-1]==walkable){answer.push_back(EnumHW_inv({i,j-1}));}if(j+1(T \times ...)^{< \omega}を持つグラフに相当する型。 // 構築 O(1)/O(|V_G|)(未初期化/初期化) // Next()の反復でinitから到達可能な頂点を全探索 O(initの連結成分における辺の本数) // Next()の反復とShift()で全探索 O(|V_G|+|E_G|) // initからの到達可能性判定と深さ計算 O(initの連結成分における辺の本数) // 連結成分の色分けと数え上げ O(|V_G|+|E_G|) template class VirtualBreadthFirstSearch { protected: GRAPH& m_G; // 未訪問点のm_prevに格納するための変数。m_nextが空の時のNext()の戻り値。 T m_not_found; bool m_initialised; // 次の探索点たちを格納。 list m_next; // 以下GRAPHがGraphでない場合は添字にEnumerationが絡むことに注意。 // m_nextに格納されたことがあるか否か。 vector m_found; // 到達済みかつ到達済みの点から辺を辿ってNext()で到達した場合、その点を格納。 // GRAPHがGraphでない場合は添字にEnumerationが絡むことに注意。 vector m_prev; public: inline VirtualBreadthFirstSearch( GRAPH& G , const T& not_found ); template inline VirtualBreadthFirstSearch( GRAPH& G , const T& not_found , Arg&& init ); // m_nextとm_foundとm_prevを初期化する。 inline void Initialise(); // m_nextとm_foundとm_prevを初期化した上でinitを最初の探索点に設定する。 inline void Initialise( const T& init ); inline void Initialise( list inits ); // m_nextを初期化した上でm_foundとm_prevを非初期化せずinitを次の探索点に設定する。 inline void Shift( const T& init ); inline void Shift( list inits ); inline const int& size() const noexcept; inline vector::reference found( const T& t ); inline const T& prev( const T& t ); inline T Next(); // 以下T==intかつGRAPHがGraphである場合にのみサポート。 // m_nextに格納されている未到達点(初期化時点ではinit/inits)から到達できる未到達点の深さを格納し、 // 到達できない未到達点や既到達点は深さの代わりに-1を格納。 vector GetDistance(); // 無向グラフである場合にのみサポート。 // 未到達点の全体のなす部分グラフにおける連結成分の色分けと連結成分数を格納。 void SetConnectedComponent( vector& cc_num , int& count ); private: virtual void Push( list& next , const T& t ) = 0; template inline void Push( list& next , const PATH& p ); }; template class BreadthFirstSearch : public VirtualBreadthFirstSearch { public: template inline BreadthFirstSearch( GRAPH& G , const T& not_found , Args&&... args ); private: inline void Push( list& next , const T& t ); }; template inline VirtualBreadthFirstSearch::VirtualBreadthFirstSearch( GRAPH& G , const T& not_found ) : m_G( G ) , m_not_found( not_found ) , m_initialised( false ) , m_next() , m_found() , m_prev() {} template template inline VirtualBreadthFirstSearch::VirtualBreadthFirstSearch( GRAPH& G , const T& not_found , Arg&& init ) : VirtualBreadthFirstSearch( G , not_found ) { Initialise( forward( init ) ); } template inline void VirtualBreadthFirstSearch::Initialise() { m_initialised = true; const int& V = size(); m_next.clear(); m_found = vector( V ); m_prev = vector( V , m_not_found ); } template inline void VirtualBreadthFirstSearch::Initialise( const T& init ) { auto&& i = m_G.Enumeration_inv( init ); assert( 0 <= i && i < size() ); Initialise(); m_next.push_back( init ); m_found[i] = true; } template inline void VirtualBreadthFirstSearch::Initialise( list inits ) { Initialise(); m_next = move( inits ); const int& V = size(); for( auto itr = m_next.begin() , end = m_next.end() ; itr != end ; itr++ ){ auto&& i = m_G.Enumeration_inv( *itr ); assert( 0 <= i && i < V ); m_found[i] = true; } } template inline void VirtualBreadthFirstSearch::Shift( const T& init ) { if( m_initialised ){ const int& V = size(); auto&& i = m_G.Enumeration_inv( init ); assert( 0 <= i && i < V ); m_next.clear(); if( ! m_found[i] ){ m_next.push_back( init ); m_found[i] = true; } } else { Initialise( init ); } } template inline void VirtualBreadthFirstSearch::Shift( list inits ) { if( m_initialised ){ m_next.clear(); const int& V = size(); for( auto itr = m_next.begin() , end = m_next.end() ; itr != end ; itr++ ){ auto&& i = m_G.Enumeration_inv( *itr ); assert( 0 <= i && i < V ); if( ! m_found[i] ){ m_next.push_back( *itr ); m_found[i] = true; } } } else { Initialise( move( inits ) ); } } template inline const int& VirtualBreadthFirstSearch::size() const noexcept { return m_G.size(); } template inline vector::reference VirtualBreadthFirstSearch::found( const T& t ) { auto&& i = m_G.Enumeration_inv( t ); assert( 0 <= i && i < size() ); if( !m_initialised ){ Initialise(); } return m_found[i]; } template inline const T& VirtualBreadthFirstSearch::prev( const T& t ) { auto&& i = m_G.Enumeration_inv( t ); assert( 0 <= i && i < size() ); if( !m_initialised ){ Initialise(); } return m_prev[i]; } template inline T VirtualBreadthFirstSearch::Next() { if( m_next.empty() ){ return m_not_found; } const T t_curr = m_next.front(); m_next.pop_front(); auto&& edge = m_G.Edge( t_curr ); for( auto& t : edge ){ auto&& i = m_G.Enumeration_inv( t ); auto&& found_i = m_found[i]; if( ! found_i ){ Push( m_next , t ); m_prev[i] = t_curr; found_i = true; } } return t_curr; } template vector VirtualBreadthFirstSearch::GetDistance() { static_assert( is_same_v && is_same_v> ); vector depth{}; depth = vector( size() , -1 ); for( auto itr = m_next.begin() , end = m_next.end() ; itr != end ; itr++ ){ depth[*itr] = 0; } int i; while( ( i = Next() ) != m_not_found ){ int& depth_i = depth[i]; depth_i == -1 ? depth_i = depth[prev( i )] + 1 : depth_i; } return depth; } template void VirtualBreadthFirstSearch::SetConnectedComponent( vector& cc_num , int& count ) { static_assert( is_same_v && is_same_v> ); const int& V = size(); cc_num = vector( V , -1 ); count = 0; for( int i = 0 ; i < V ; i++ ){ if( cc_num[i] == -1 ){ Shift( i ); int j = Next(); if( j != m_not_found ){ while( j != m_not_found ){ // 無向グラフである場合は常にtrue。 assert( cc_num[j] == -1 ); cc_num[j] = count; j = Next(); } count++; } } } return; } template template inline void VirtualBreadthFirstSearch::Push( list& next , const PATH& p ) { Push( next , get<0>( p ) ); } template template inline BreadthFirstSearch::BreadthFirstSearch( GRAPH& G , const T& not_found , Args&&... args ) : VirtualBreadthFirstSearch( G , not_found , forward( args )... ) {} template inline void BreadthFirstSearch::Push( list& next , const T& t ) { next.push_back( t ); } // AAA ライブラリは以上に挿入する。 #define INCLUDE_MAIN #include __FILE__ #else // INCLUDE_LIBRARY #ifdef DEBUG #define _GLIBCXX_DEBUG #define SIGNAL signal( SIGABRT , &AlertAbort ); #define DEXPR( LL , BOUND , VALUE1 , VALUE2 ) CEXPR( LL , BOUND , VALUE2 ) #define ASSERT( A , MIN , MAX ) CERR( "ASSERTチェック: " , ( MIN ) , ( ( MIN ) <= A ? "<=" : ">" ) , A , ( A <= ( MAX ) ? "<=" : ">" ) , ( MAX ) ); assert( ( MIN ) <= A && A <= ( MAX ) ) #define CERR( ... ) VariadicCout( cerr , __VA_ARGS__ ) << endl #define COUT( ... ) VariadicCout( cout << "出力: " , __VA_ARGS__ ) << endl #define CERR_A( A , N ) OUTPUT_ARRAY( cerr , A , N ) << endl #define COUT_A( A , N ) cout << "出力: "; OUTPUT_ARRAY( cout , A , N ) << endl #define CERR_ITR( A ) OUTPUT_ITR( cerr , A ) << endl #define COUT_ITR( A ) cout << "出力: "; OUTPUT_ITR( cout , A ) << endl #else #pragma GCC optimize ( "O3" ) #pragma GCC optimize ( "unroll-loops" ) #pragma GCC target ( "sse4.2,fma,avx2,popcnt,lzcnt,bmi2" ) #define SIGNAL #define DEXPR( LL , BOUND , VALUE1 , VALUE2 ) CEXPR( LL , BOUND , VALUE1 ) #define ASSERT( A , MIN , MAX ) assert( ( MIN ) <= A && A <= ( MAX ) ) #define CERR( ... ) #define COUT( ... ) VariadicCout( cout , __VA_ARGS__ ) << ENDL #define CERR_A( A , N ) #define COUT_A( A , N ) OUTPUT_ARRAY( cout , A , N ) << ENDL #define CERR_ITR( A ) #define COUT_ITR( A ) OUTPUT_ITR( cout , A ) << ENDL #endif #ifdef REACTIVE #define ENDL endl #else #define ENDL "\n" #endif #ifdef USE_GETLINE #define SET_LL( A ) { GETLINE( A ## _str ); A = stoll( A ## _str ); } #define GETLINE_SEPARATE( SEPARATOR , ... ) string __VA_ARGS__; VariadicGetline( cin , SEPARATOR , __VA_ARGS__ ) #define GETLINE( ... ) GETLINE_SEPARATE( '\n' , __VA_ARGS__ ) #else #define SET_LL( A ) cin >> A #define CIN( LL , ... ) LL __VA_ARGS__; VariadicCin( cin , __VA_ARGS__ ) #define SET_A( A , N ) FOR( VARIABLE_FOR_SET_A , 0 , N ){ cin >> A[VARIABLE_FOR_SET_A]; } #define CIN_A( LL , A , N ) vector A( N ); SET_A( A , N ); #endif #include using namespace std; #define REPEAT_MAIN( BOUND ) int main(){ ios_base::sync_with_stdio( false ); cin.tie( nullptr ); SIGNAL; CEXPR( int , bound_test_case_num , BOUND ); int test_case_num = 1; if constexpr( bound_test_case_num > 1 ){ CERR( "テストケースの個数を入力してください。" ); SET_ASSERT( test_case_num , 1 , bound_test_case_num ); } REPEAT( test_case_num ){ if constexpr( bound_test_case_num > 1 ){ CERR( "testcase " , VARIABLE_FOR_REPEAT_test_case_num , ":" ); } Solve(); CERR( "" ); } } #define START_WATCH chrono::system_clock::time_point watch = chrono::system_clock::now() #define CURRENT_TIME static_cast( chrono::duration_cast( chrono::system_clock::now() - watch ).count() / 1000.0 ) #define CHECK_WATCH( TL_MS ) ( CURRENT_TIME < TL_MS - 100.0 ) #define CEXPR( LL , BOUND , VALUE ) constexpr LL BOUND = VALUE #define SET_ASSERT( A , MIN , MAX ) SET_LL( A ); ASSERT( A , MIN , MAX ) #define SET_A_ASSERT( A , N , MIN , MAX ) FOR( VARIABLE_FOR_SET_A , 0 , N ){ SET_ASSERT( A[VARIABLE_FOR_SET_A] , MIN , MAX ); } #define CIN_ASSERT( A , MIN , MAX ) decldecay_t( MAX ) A; SET_ASSERT( A , MIN , MAX ) #define CIN_A_ASSERT( A , N , MIN , MAX ) vector A( N ); SET_A_ASSERT( A , N , MIN , MAX ) #define FOR( VAR , INITIAL , FINAL_PLUS_ONE ) for( decldecay_t( FINAL_PLUS_ONE ) VAR = INITIAL ; VAR < FINAL_PLUS_ONE ; VAR ++ ) #define FOREQ( VAR , INITIAL , FINAL ) for( decldecay_t( FINAL ) VAR = INITIAL ; VAR <= FINAL ; VAR ++ ) #define FOREQINV( VAR , INITIAL , FINAL ) for( decldecay_t( INITIAL ) VAR = INITIAL ; VAR + 1 > FINAL ; VAR -- ) #define AUTO_ITR( ARRAY ) auto itr_ ## ARRAY = ARRAY .begin() , end_ ## ARRAY = ARRAY .end() #define FOR_ITR( ARRAY ) for( AUTO_ITR( ARRAY ) , itr = itr_ ## ARRAY ; itr_ ## ARRAY != end_ ## ARRAY ; itr_ ## ARRAY ++ , itr++ ) #define REPEAT( HOW_MANY_TIMES ) FOR( VARIABLE_FOR_REPEAT_ ## HOW_MANY_TIMES , 0 , HOW_MANY_TIMES ) #define SET_PRECISION( DECIMAL_DIGITS ) cout << fixed << setprecision( DECIMAL_DIGITS ) #define OUTPUT_ARRAY( OS , A , N ) FOR( VARIABLE_FOR_OUTPUT_ARRAY , 0 , N ){ OS << A[VARIABLE_FOR_OUTPUT_ARRAY] << (VARIABLE_FOR_OUTPUT_ARRAY==N-1?"":" "); } OS #define OUTPUT_ITR( OS , A ) { auto ITERATOR_FOR_OUTPUT_ITR = A.begin() , END_FOR_OUTPUT_ITR = A.end(); bool VARIABLE_FOR_OUTPUT_ITR = ITERATOR_FOR_COUT_ITR != END_FOR_COUT_ITR; while( VARIABLE_FOR_OUTPUT_ITR ){ OS << *ITERATOR_FOR_COUT_ITR; ( VARIABLE_FOR_OUTPUT_ITR = ++ITERATOR_FOR_COUT_ITR != END_FOR_COUT_ITR ) ? OS : OS << " "; } } OS #define RETURN( ... ) COUT( __VA_ARGS__ ); return // 型のエイリアス #define decldecay_t( VAR ) decay_t template using ret_t = decltype( declval()( declval()... ) ); template using inner_t = typename T::type; using uint = unsigned int; using ll = long long; using ull = unsigned long long; using ld = long double; using lld = __float128; template using T2 = pair; template using T3 = tuple; template using T4 = tuple; using path = pair; // 入出力用 template inline basic_istream& VariadicCin( basic_istream& is ) { return is; } template inline basic_istream& VariadicCin( basic_istream& is , Arg& arg , ARGS&... args ) { return VariadicCin( is >> arg , args... ); } template inline basic_istream& VariadicGetline( basic_istream& is , const char& separator ) { return is; } template inline basic_istream& VariadicGetline( basic_istream& is , const char& separator , Arg& arg , ARGS&... args ) { return VariadicGetline( getline( is , arg , separator ) , separator , args... ); } template inline basic_ostream& operator<<( basic_ostream& os , const vector& arg ) { auto begin = arg.begin() , end = arg.end(); auto itr = begin; while( itr != end ){ ( itr == begin ? os : os << " " ) << *itr; itr++; } return os; } template inline basic_ostream& operator<<( basic_ostream& os , const pair& arg ) { return os << arg.first << " " << arg.second; } template inline basic_ostream& VariadicCout( basic_ostream& os , const Arg& arg ) { return os << arg; } template inline basic_ostream& VariadicCout( basic_ostream& os , const Arg1& arg1 , const Arg2& arg2 , const ARGS&... args ) { return VariadicCout( os << arg1 << " " , arg2 , args... ); } // デバッグ用 #ifdef DEBUG inline void AlertAbort( int n ) { CERR( "abort関数が呼ばれました。assertマクロのメッセージが出力されていない場合はオーバーフローの有無を確認をしてください。" ); } void AutoCheck( bool& auto_checked ); #endif #define INCLUDE_LIBRARY #include __FILE__ #endif // INCLUDE_LIBRARY #endif // INCLUDE_MAIN