#pragma GCC optimize ( "O3" ) #pragma GCC optimize( "unroll-loops" ) #pragma GCC target ( "sse4.2,fma,avx2,popcnt,lzcnt,bmi2" ) #include #include #include #include #include using namespace std; using ll = long long; #define MAIN main #define TYPE_OF( VAR ) remove_const::type >::type #define CEXPR( LL , BOUND , VALUE ) constexpr const LL BOUND = VALUE #define CIN( LL , A ) LL A; cin >> A #define ASSERT( A , MIN , MAX ) assert( MIN <= A && A <= MAX ) #define CIN_ASSERT( A , MIN , MAX ) CIN( TYPE_OF( MAX ) , A ); ASSERT( A , MIN , MAX ) #define FOR( VAR , INITIAL , FINAL_PLUS_ONE ) for( TYPE_OF( FINAL_PLUS_ONE ) VAR = INITIAL ; VAR < FINAL_PLUS_ONE ; VAR ++ ) #define REPEAT( HOW_MANY_TIMES ) FOR( VARIABLE_FOR_REPEAT , 0 , HOW_MANY_TIMES ) #define QUIT return 0 #define COUT( ANSWER ) cout << ( ANSWER ) << "\n" #define RETURN( ANSWER ) COUT( ANSWER ); QUIT #define POWER( ANSWER , ARGUMENT , EXPONENT ) \ TYPE_OF( ARGUMENT ) ANSWER{ 1 }; \ { \ TYPE_OF( ARGUMENT ) ARGUMENT_FOR_SQUARE_FOR_POWER = ( ARGUMENT ); \ TYPE_OF( EXPONENT ) EXPONENT_FOR_SQUARE_FOR_POWER = ( EXPONENT ); \ while( EXPONENT_FOR_SQUARE_FOR_POWER != 0 ){ \ if( EXPONENT_FOR_SQUARE_FOR_POWER % 2 == 1 ){ \ ANSWER *= ARGUMENT_FOR_SQUARE_FOR_POWER; \ } \ ARGUMENT_FOR_SQUARE_FOR_POWER *= ARGUMENT_FOR_SQUARE_FOR_POWER; \ EXPONENT_FOR_SQUARE_FOR_POWER /= 2; \ } \ } \ template class QuotientRing { protected: INT m_n; const INT* m_p_M; public: inline QuotientRing() noexcept; inline QuotientRing( const INT& n , const INT* const & p_M = nullptr ) noexcept; inline QuotientRing( const QuotientRing& n ) noexcept; inline QuotientRing& operator+=( const QuotientRing& n ) noexcept; inline QuotientRing& operator+=( const INT& n ) noexcept; // operator<が定義されていても負の数は正に直さず剰余を取ることに注意。 inline QuotientRing& operator-=( const QuotientRing& n ) noexcept; inline QuotientRing& operator-=( const INT& n ) noexcept; inline QuotientRing& operator*=( const QuotientRing& n ) noexcept; inline QuotientRing& operator*=( const INT& n ) noexcept; inline const INT& Represent() const noexcept; inline const INT& GetModulo() const noexcept; // m_nの正負やm_p_Mの一致込みの等号。 static inline bool Equal( const QuotientRing& n0 , const QuotientRing& n1 ) noexcept; template static QuotientRing Power( const QuotientRing& n , const T& exponent ); }; template inline bool operator==( const QuotientRing& n0 , const QuotientRing& n1 ) noexcept; template inline bool operator!=( const QuotientRing& n0 , const QuotientRing& n1 ) noexcept; template inline QuotientRing operator+( const QuotientRing& n0 , const T& n1 ) noexcept; template inline QuotientRing operator-( const QuotientRing& n0 , const T& n1 ) noexcept; template inline QuotientRing operator*( const QuotientRing& n0 , const T& n1 ) noexcept; template inline QuotientRing Power( const QuotientRing& n , const T& exponent ); template inline QuotientRing::QuotientRing() noexcept : m_n() , m_p_M( nullptr ) {} template inline QuotientRing::QuotientRing( const INT& n , const INT* const & p_M ) noexcept : m_n( p_M == nullptr ? n : n % *p_M ) , m_p_M( p_M ) {} template inline QuotientRing::QuotientRing( const QuotientRing& n ) noexcept : m_n( n.m_n ) , m_p_M( n.m_p_M ) {} template inline QuotientRing& QuotientRing::operator+=( const QuotientRing& n ) noexcept { if( m_p_M == nullptr ){ m_p_M = n.m_p_M; } m_n += n.m_n; if( m_p_M != nullptr ){ m_n %= *m_p_M; } return *this; } template inline QuotientRing& QuotientRing::operator+=( const INT& n ) noexcept { m_n += n; if( m_p_M != nullptr ){ m_n %= *m_p_M; } return *this; } template inline QuotientRing& QuotientRing::operator-=( const QuotientRing& n ) noexcept { if( m_p_M == nullptr ){ m_p_M = n.m_p_M; } m_n -= n.m_n; if( m_p_M != nullptr ){ m_n %= *m_p_M; } return *this; } template inline QuotientRing& QuotientRing::operator-=( const INT& n ) noexcept { m_n -= n; if( m_p_M != nullptr ){ m_n %= *m_p_M; } return *this; } template inline QuotientRing& QuotientRing::operator*=( const QuotientRing& n ) noexcept { if( m_p_M == nullptr ){ m_p_M = n.m_p_M; } m_n *= n.m_n; if( m_p_M != nullptr ){ m_n %= *m_p_M; } return *this; } template inline QuotientRing& QuotientRing::operator*=( const INT& n ) noexcept { m_n *= n; if( m_p_M != nullptr ){ m_n %= *m_p_M; } return *this; } template inline const INT& QuotientRing::Represent() const noexcept { return m_n; } template inline const INT& QuotientRing::GetModulo() const noexcept { static const INT zero{ 0 }; return m_p_M == nullptr ? zero : *m_p_M; } template inline bool QuotientRing::Equal( const QuotientRing& n0 , const QuotientRing& n1 ) noexcept { return n0.m_n == n1.m_n && n0.m_p_M == n1.m_p_M; } template template QuotientRing QuotientRing::Power( const QuotientRing& n , const T& exponent ) { QuotientRing answer{ 1 , n.m_p_M }; QuotientRing power{ n }; while( exponent != 0 ){ if( exponent % 2 == 1 ){ answer *= power; } power *= power; exponent /= 2; } return answer; } template inline bool operator==( const QuotientRing& n0 , const QuotientRing& n1 ) noexcept { return QuotientRing::Equal( n0 , n1 ); } template inline bool operator!=( const QuotientRing& n0 , const QuotientRing& n1 ) noexcept { return ! QuotientRing::Equal( n0 , n1 ); } template inline QuotientRing operator+( const QuotientRing& n0 , const T& n1 ) noexcept { return QuotientRing( n0 ).operator+=( n1 ); } template inline QuotientRing operator-( const QuotientRing& n0 , const T& n1 ) noexcept { return QuotientRing( n0 ).operator-=( n1 ); } template inline QuotientRing operator*( const QuotientRing& n0 , const T& n1 ) noexcept { return QuotientRing( n0 ).operator*=( n1 ); } template inline QuotientRing Power( const QuotientRing& n , const T& exponent ) { return QuotientRing::template Power( n , exponent ); } template class QuadraticExtension { private: INT m_a; INT m_b; const INT* m_p_D; public: inline QuadraticExtension() noexcept; template inline QuadraticExtension( const T& a ) noexcept; inline QuadraticExtension( const INT& a , const INT& b , const INT* const & p_D ) noexcept; inline QuadraticExtension( const QuadraticExtension& n ) noexcept; inline const INT& GetA() const noexcept; inline const INT& GetB() const noexcept; inline const INT& GetD() const noexcept; inline QuadraticExtension& operator+=( const QuadraticExtension& n ) noexcept; template inline QuadraticExtension& operator+=( const T& a ) noexcept; inline QuadraticExtension& operator-=( const QuadraticExtension& n ) noexcept; template inline QuadraticExtension& operator-=( const T& a ) noexcept; // 3数の乗法が入るのでオーバーフローに注意 // 10^6より大きいmodで計算する時はINTにModなどを代入するか乗法の定義を修正する inline QuadraticExtension& operator*=( const QuadraticExtension& n ) noexcept; template inline QuadraticExtension& operator*=( const T& a ) noexcept; template inline QuadraticExtension& operator/=( const T& a ) noexcept; template inline QuadraticExtension& operator%=( const T& a ) noexcept; // m_p_Dの一致込みの等号 static inline bool Equal( const QuadraticExtension& n0 , const QuadraticExtension& n1 ) noexcept; private: static inline const INT& Zero() noexcept; }; template inline bool operator==( const QuadraticExtension& n0 , const QuadraticExtension& n1 ) noexcept; template inline bool operator!=( const QuadraticExtension& n0 , const QuadraticExtension& n1 ) noexcept; template inline QuadraticExtension operator+( const QuadraticExtension& n , const T& a ) noexcept; template inline QuadraticExtension operator-( const QuadraticExtension& n , const T& a ) noexcept; template inline QuadraticExtension operator*( const QuadraticExtension& n , const T& a ) noexcept; template inline QuadraticExtension operator/( const QuadraticExtension& n , const T& a ) noexcept; template inline QuadraticExtension operator%( const QuadraticExtension& n , const T& a ) noexcept; // Dは一時変数でない変数 template inline QuadraticExtension Sqrt( const INT& D ) noexcept; template inline QuadraticExtension::QuadraticExtension() noexcept : m_a() , m_b() , m_p_D( nullptr ) {} template template inline QuadraticExtension::QuadraticExtension( const T& a ) noexcept : m_a( a ) , m_b() , m_p_D( nullptr ) {} template inline QuadraticExtension::QuadraticExtension( const INT& a , const INT& b , const INT* const & p_D ) noexcept : m_a( a ) , m_b( b ) , m_p_D( p_D ) {} template inline QuadraticExtension::QuadraticExtension( const QuadraticExtension& n ) noexcept : m_a( n.m_a ) , m_b( n.m_b ) , m_p_D( n.m_p_D ) {} template inline const INT& QuadraticExtension::GetA() const noexcept { return m_a; } template inline const INT& QuadraticExtension::GetB() const noexcept { return m_b; } template inline const INT& QuadraticExtension::GetD() const noexcept { return m_p_D == nullptr ? Zero() : *m_p_D; } template inline QuadraticExtension& QuadraticExtension::operator+=( const QuadraticExtension& n ) noexcept { if( m_p_D == nullptr ){ m_p_D = n.m_p_D; } m_a += n.m_a; m_b += n.m_b; return *this; } template template inline QuadraticExtension& QuadraticExtension::operator+=( const T& a ) noexcept { m_a += a; return *this; } template inline QuadraticExtension& QuadraticExtension::operator-=( const QuadraticExtension& n ) noexcept { if( m_p_D == nullptr ){ m_p_D = n.m_p_D; } m_a -= n.m_a; m_b -= n.m_b; return *this; } template template inline QuadraticExtension& QuadraticExtension::operator-=( const T& a ) noexcept { m_a -= a; return *this; } template inline QuadraticExtension& QuadraticExtension::operator*=( const QuadraticExtension& n ) noexcept { if( m_p_D == nullptr ){ m_p_D = n.m_p_D; } const INT a = ( m_p_D == nullptr ? m_a * n.m_a : m_a * n.m_a + m_b * n.m_b * ( *m_p_D ) ); m_b = m_a * n.m_b + m_b * n.m_a; m_a = a; return *this; } template template inline QuadraticExtension& QuadraticExtension::operator*=( const T& a ) noexcept { m_a *= a; m_b *= a; return *this; } template template inline QuadraticExtension& QuadraticExtension::operator/=( const T& a ) noexcept { m_a /= a; m_b /= a; return *this; } template template inline QuadraticExtension& QuadraticExtension::operator%=( const T& a ) noexcept { m_a %= a; m_b %= a; return *this; } template inline bool QuadraticExtension::Equal( const QuadraticExtension& n0 , const QuadraticExtension& n1 ) noexcept { return n0.m_a == n1.m_a && n0.m_b == n1.m_b && n0.m_p_D == n1.m_p_D; } template inline const INT& QuadraticExtension::Zero() noexcept { static const INT zero{ 0 }; return zero; } template inline bool operator==( const QuadraticExtension& n0 , const QuadraticExtension& n1 ) noexcept { return QuadraticExtension::Equal( n0 , n1 ); } template inline bool operator!=( const QuadraticExtension& n0 , const QuadraticExtension& n1 ) noexcept { return ! QuadraticExtension::Equal( n0 , n1 ); } template inline QuadraticExtension operator+( const QuadraticExtension& n , const T& a ) noexcept { return QuadraticExtension( n ).operator+=( a ); } template inline QuadraticExtension operator-( const QuadraticExtension& n , const T& a ) noexcept { return QuadraticExtension( n ).operator-=( a ); } template inline QuadraticExtension operator*( const QuadraticExtension& n , const T& a ) noexcept { return QuadraticExtension( n ).operator*=( a ); } template inline QuadraticExtension operator/( const QuadraticExtension& n , const T& a ) noexcept { return QuadraticExtension( n ).operator/=( a ); } template inline QuadraticExtension operator%( const QuadraticExtension& n , const T& a ) noexcept { return QuadraticExtension( n ).operator%=( a ); } template inline QuadraticExtension Sqrt( const INT& D ) noexcept { return QuadraticExtension( 0 , 1 , &D ); } int MAIN() { CEXPR( int , bound_T , 10000 ); CIN_ASSERT( T , 1 , bound_T ); CEXPR( ll , bound_NML , 1000000000000000000 ); CEXPR( ll , bound_B , 1000000000 ); REPEAT( T ){ CIN_ASSERT( N , 1 , bound_NML ); CIN_ASSERT( M_base , 1 , bound_NML ); CIN_ASSERT( L_base , 1 , bound_NML ); CIN_ASSERT( B , 1 , bound_B ); QuotientRing M{ M_base , &B }; QuadraticExtension > L{ QuotientRing( L_base , &B ) , 0 , &M }; QuadraticExtension > > sqrtM{ Sqrt >( M ) }; QuadraticExtension > > sqrtL = Sqrt > >( L ); POWER( power , sqrtM + sqrtL , N ); const QuadraticExtension >& power_coeff = N % 2 == 0 ? power.GetA() : power.GetB(); COUT( power_coeff.GetA().Represent() ); } QUIT; }