#include using namespace std; using uint = unsigned int; using ll = long long; #define CIN( LL , A ) LL A; cin >> A #define UNTIE ios_base::sync_with_stdio( false ); cin.tie( nullptr ) #define FOR( VAR , INITIAL , FINAL_PLUS_ONE ) for( ll VAR = INITIAL ; VAR < FINAL_PLUS_ONE ; VAR ++ ) #define RETURN( ANSWER ) cout << ( ANSWER ) << "\n"; return 0 // 以下、自分のライブラリ(https://github.com/p-adic/cpp)よりソースコードをコピーして編集している。 template INT Residue( const INT& M , const INT& n ) noexcept; template INT Residue( const INT& M , const INT& n ) noexcept { if( M == 0 ){ return 0; } const INT M_abs = ( M > 0 ? M : -M ); if( n < 0 ){ const INT n_abs = -n; const INT res = n_abs % M_abs; return res == 0 ? res : M_abs - res; } return n % M_abs; } template using VLArray = list; using INT_TYPE_FOR_MOD = long long int; // ここをtempate などにしてしまうとoperator+などを呼び出す際に型推論に失敗する。整数型を変えたい時はINT_TYPE_FOR_MODの型エイリアスを変更する。 template class Mod { protected: INT_TYPE_FOR_MOD m_n; INT_TYPE_FOR_MOD m_inv; public: inline Mod() noexcept; inline Mod( const INT_TYPE_FOR_MOD& n ) noexcept; inline Mod( const Mod& n ) noexcept; inline Mod& operator=( const INT_TYPE_FOR_MOD& n ) noexcept; Mod& operator=( const Mod& n ) noexcept; Mod& operator+=( const INT_TYPE_FOR_MOD& n ) noexcept; inline Mod& operator+=( const Mod& n ) noexcept; inline Mod& operator-=( const INT_TYPE_FOR_MOD& n ) noexcept; inline Mod& operator-=( const Mod& n ) noexcept; Mod& operator*=( const INT_TYPE_FOR_MOD& n ) noexcept; Mod& operator*=( const Mod& n ) noexcept; // INT_TYPE_FOR_MODでの割り算ではないことに注意 virtual Mod& operator/=( const INT_TYPE_FOR_MOD& n ); virtual Mod& operator/=( const Mod& n ); Mod& operator%=( const INT_TYPE_FOR_MOD& n ); inline Mod& operator%=( const Mod& n ); inline Mod operator-() const noexcept; // 前置++/--を使うつもりがないので後置++/--と同じものとして定義する inline Mod& operator++() noexcept; inline Mod& operator++( int ) noexcept; inline Mod& operator--() noexcept; inline Mod& operator--( int ) noexcept; inline const INT_TYPE_FOR_MOD& Represent() const noexcept; void Invert() noexcept; bool CheckInvertible() noexcept; bool IsSmallerThan( const INT_TYPE_FOR_MOD& n ) const noexcept; bool IsBiggerThan( const INT_TYPE_FOR_MOD& n ) const noexcept; }; template inline bool operator==( const Mod& n0 , const INT_TYPE_FOR_MOD& n1 ) noexcept; template inline bool operator==( const INT_TYPE_FOR_MOD& n0 , const Mod& n1 ) noexcept; template inline bool operator==( const Mod& n0 , const Mod& n1 ) noexcept; template inline bool operator==( const Mod& n0 , const Mod& n1 ) noexcept; template inline bool operator!=( const Mod& n0 , const INT_TYPE_FOR_MOD& n1 ) noexcept; template inline bool operator!=( const INT_TYPE_FOR_MOD& n0 , const Mod& n1 ) noexcept; template inline bool operator!=( const Mod& n0 , const Mod& n1 ) noexcept; template inline bool operator!=( const Mod& n0 , const Mod& n1 ) noexcept; template inline bool operator<( const Mod& n0 , const INT_TYPE_FOR_MOD& n1 ) noexcept; template inline bool operator<( const INT_TYPE_FOR_MOD& n0 , const Mod& n1 ) noexcept; template inline bool operator<( const Mod& n0 , const Mod& n1 ) noexcept; template inline bool operator<=( const Mod& n0 , const INT_TYPE_FOR_MOD& n1 ) noexcept; template inline bool operator<=( const INT_TYPE_FOR_MOD& n0 , const Mod& n1 ) noexcept; template inline bool operator<=( const Mod& n0 , const Mod& n1 ) noexcept; template inline bool operator<=( const Mod& n0 , const Mod& n1 ) noexcept; template inline bool operator>( const Mod& n0 , const INT_TYPE_FOR_MOD& n1 ) noexcept; template inline bool operator>( const INT_TYPE_FOR_MOD& n0 , const Mod& n1 ) noexcept; template inline bool operator>( const Mod& n0 , const Mod& n1 ) noexcept; template inline bool operator>( const Mod& n0 , const Mod& n1 ) noexcept; template inline bool operator>=( const Mod& n0 , const INT_TYPE_FOR_MOD& n1 ) noexcept; template inline bool operator>=( const INT_TYPE_FOR_MOD& n0 , const Mod& n1 ) noexcept; template inline bool operator>=( const Mod& n0 , const Mod& n1 ) noexcept; template inline bool operator>=( const Mod& n0 , const Mod& n1 ) noexcept; template Mod operator+( const Mod& n0 , const INT_TYPE_FOR_MOD& n1 ) noexcept; template Mod operator+( const INT_TYPE_FOR_MOD& n0 , const Mod& n1 ) noexcept; template Mod operator+( const Mod& n0 , const Mod& n1 ) noexcept; template inline Mod operator-( const Mod& n0 , const INT_TYPE_FOR_MOD& n1 ) noexcept; template Mod operator-( const INT_TYPE_FOR_MOD& n0 , const Mod& n1 ) noexcept; template Mod operator-( const Mod& n0 , const Mod& n1 ) noexcept; template Mod operator*( const Mod& n0 , const INT_TYPE_FOR_MOD& n1 ) noexcept; template Mod operator*( const INT_TYPE_FOR_MOD& n0 , const Mod& n1 ) noexcept; template Mod operator*( const Mod& n0 , const Mod& n1 ) noexcept; template Mod operator/( const Mod& n0 , const INT_TYPE_FOR_MOD& n1 ); template Mod operator/( const INT_TYPE_FOR_MOD& n0 , const Mod& n1 ); template Mod operator/( const Mod& n0 , const Mod& n1 ); template Mod operator%( const Mod& n0 , const INT_TYPE_FOR_MOD& n1 ); template inline Mod operator%( const INT_TYPE_FOR_MOD& n0 , const Mod& n1 ); template inline Mod operator%( const Mod& n0 , const Mod& n1 ); template Mod Inverse( const Mod& n ); template Mod Power( const Mod& n , const INT_TYPE_FOR_MOD& p , const string& method = "normal" ); template <> inline Mod<2> Power( const Mod<2>& n , const INT_TYPE_FOR_MOD& p , const string& method ); // M乗が1になるよう定義されていることに注意 template inline Mod Power( const Mod& n , const Mod& p , const string& method = "normal" ); template <> inline Mod<2> Power( const Mod<2>& n , const Mod<2>& p , const string& method ); // ../Power/a_Body.hppにて定義 template inline T Square( const T& t ); template <> inline Mod<2> Square >( const Mod<2>& t ); template inline string to_string( const Mod& n ) noexcept; void LazyEvaluationOfModularInverse( const INT_TYPE_FOR_MOD& M , const INT_TYPE_FOR_MOD& n , INT_TYPE_FOR_MOD& m ); template inline Mod::Mod() noexcept : m_n( 0 ) , m_inv( M ){} template inline Mod::Mod( const INT_TYPE_FOR_MOD& n ) noexcept : m_n( Residue( M , n ) ) , m_inv( 0 ){} template inline Mod::Mod( const Mod& n ) noexcept : m_n( n.m_n ) , m_inv( 0 ){} template inline Mod& Mod::operator=( const INT_TYPE_FOR_MOD& n ) noexcept { return operator=( Mod( n ) ); } template Mod& Mod::operator=( const Mod& n ) noexcept { m_n = n.m_n; m_inv = n.m_inv; return *this; } template Mod& Mod::operator+=( const INT_TYPE_FOR_MOD& n ) noexcept { m_n = Residue( M , m_n + n ); m_inv = 0; return *this; } template inline Mod& Mod::operator+=( const Mod& n ) noexcept { return operator+=( n.m_n ); }; template inline Mod& Mod::operator-=( const INT_TYPE_FOR_MOD& n ) noexcept { return operator+=( -n ); } template inline Mod& Mod::operator-=( const Mod& n ) noexcept { return operator-=( n.m_n ); } template Mod& Mod::operator*=( const INT_TYPE_FOR_MOD& n ) noexcept { m_n = Residue( M , m_n * n ); m_inv = 0; return *this; } template Mod& Mod::operator*=( const Mod& n ) noexcept { m_n = Residue( M , m_n * n.m_n ); if( m_inv == 0 || n.m_inv == 0 ){ m_inv = 0; } else if( m_inv == M || n.m_inv == M ){ m_inv = M; } else { Residue( M , m_inv * n.m_inv ); } return *this; } // 仮想関数なのでinline指定しない。 template Mod& Mod::operator/=( const INT_TYPE_FOR_MOD& n ) { return operator/=( Mod( n ) ); } template Mod& Mod::operator/=( const Mod& n ) { return operator*=( Inverse( n ) ); } template Mod& Mod::operator%=( const INT_TYPE_FOR_MOD& n ) { m_n %= Residue( M , n ); m_inv = 0; return *this; } template inline Mod& Mod::operator%=( const Mod& n ) { return operator%=( n.m_n ); } template inline Mod Mod::operator-() const noexcept { return Mod( 0 ).operator-=( *this ); } template inline Mod& Mod::operator++() noexcept { return operator+=( 1 ); } template inline Mod& Mod::operator++( int ) noexcept { return operator++(); } template inline Mod& Mod::operator--() noexcept { return operator-=( 1 ); } template inline Mod& Mod::operator--( int ) noexcept { return operator-=(); } template inline const INT_TYPE_FOR_MOD& Mod::Represent() const noexcept { return m_n; } template void Mod::Invert() noexcept { if( CheckInvertible() ){ INT_TYPE_FOR_MOD i = m_inv; m_inv = m_n; m_n = i; } else { // m_nがMになるのはここの処理に限るのでRepresent()の値を参照することで例外処理可能 m_n = M; m_inv = M; } return; } template bool Mod::CheckInvertible() noexcept { if( m_inv == 0 ){ LazyEvaluationOfModularInverse( M , m_n , m_inv ); } return m_inv != M; } template inline bool Mod::IsSmallerThan( const INT_TYPE_FOR_MOD& n ) const noexcept { return m_n < Residue( M , n ); } template inline bool Mod::IsBiggerThan( const INT_TYPE_FOR_MOD& n ) const noexcept { return m_n > Residue( M , n ); } template inline bool operator==( const Mod& n0 , const INT_TYPE_FOR_MOD& n1 ) noexcept { return n0 == Mod( n1 ); } template inline bool operator==( const INT_TYPE_FOR_MOD& n0 , const Mod& n1 ) noexcept { return Mod( n0 ) == n0; } template inline bool operator==( const Mod& n0 , const Mod& n1 ) noexcept { return n0.Represent() == n1.Represent(); } template inline bool operator!=( const Mod& n0 , const INT_TYPE_FOR_MOD& n1 ) noexcept { return !( n0 == n1 ); } template inline bool operator!=( const INT_TYPE_FOR_MOD& n0 , const Mod& n1 ) noexcept { return !( n0 == n1 ); } template inline bool operator!=( const Mod& n0 , const Mod& n1 ) noexcept { return !( n0 == n1 ); } template inline bool operator<( const Mod& n0 , const INT_TYPE_FOR_MOD& n1 ) noexcept { return n0.IsSmallerThan( n1 ); } template inline bool operator<( const INT_TYPE_FOR_MOD& n0 , const Mod& n1 ) noexcept { return n1.IsBiggerThan( n0 ); } template inline bool operator<( const Mod& n0 , const Mod& n1 ) noexcept { return n0.Represent() < n1.Represent(); } template inline bool operator<=( const Mod& n0 , const INT_TYPE_FOR_MOD& n1 ) noexcept { return !( n1 < n0 ); } template inline bool operator<=( const INT_TYPE_FOR_MOD& n0 , const Mod& n1 ) noexcept { return !( n1 < n0 ); } template inline bool operator<=( const Mod& n0 , const Mod& n1 ) noexcept { return !( n1 < n0 ); } template inline bool operator>( const Mod& n0 , const INT_TYPE_FOR_MOD& n1 ) noexcept { return n1 < n0; } template inline bool operator>( const INT_TYPE_FOR_MOD& n0 , const Mod& n1 ) noexcept { return n1 < n0; } template inline bool operator>( const Mod& n0 , const Mod& n1 ) noexcept { return n1 < n0; } template inline bool operator>=( const Mod& n0 , const INT_TYPE_FOR_MOD& n1 ) noexcept { return !( n0 < n1 ); } template inline bool operator>=( const INT_TYPE_FOR_MOD& n0 , const Mod& n1 ) noexcept { return !( n0 < n1 ); } template inline bool operator>=( const Mod& n0 , const Mod& n1 ) noexcept { return !( n0 < n1 ); } template Mod operator+( const Mod& n0 , const INT_TYPE_FOR_MOD& n1 ) noexcept { auto n = n0; n += n1; return n; } template inline Mod operator+( const INT_TYPE_FOR_MOD& n0 , const Mod& n1 ) noexcept { return n1 + n0; } template inline Mod operator+( const Mod& n0 , const Mod& n1 ) noexcept { return n0 + n1.Represent(); } template inline Mod operator-( const Mod& n0 , const INT_TYPE_FOR_MOD& n1 ) noexcept { return n0 + ( -n1 ); } template inline Mod operator-( const INT_TYPE_FOR_MOD& n0 , const Mod& n1 ) noexcept { return Mod( n0 - n1.Represent() ); } template inline Mod operator-( const Mod& n0 , const Mod& n1 ) noexcept { return n0 - n1.Represent(); } template Mod operator*( const Mod& n0 , const INT_TYPE_FOR_MOD& n1 ) noexcept { auto n = n0; n *= n1; return n; } template inline Mod operator*( const INT_TYPE_FOR_MOD& n0 , const Mod& n1 ) noexcept { return n1 * n0; } template Mod operator*( const Mod& n0 , const Mod& n1 ) noexcept { auto n = n0; n *= n1; return n; } template inline Mod operator/( const Mod& n0 , const INT_TYPE_FOR_MOD& n1 ) { return n0 / Mod( n1 ); } template inline Mod operator/( const INT_TYPE_FOR_MOD& n0 , const Mod& n1 ) { return Mod( n0 ) / n1; } template Mod operator/( const Mod& n0 , const Mod& n1 ) { auto n = n0; n /= n1; return n; } template Mod operator%( const Mod& n0 , const INT_TYPE_FOR_MOD& n1 ) { auto n = n0; n %= n1; return n; } template inline Mod operator%( const INT_TYPE_FOR_MOD& n0 , const Mod& n1 ) { return Mod( n0 ) % n1.Represent(); } template inline Mod operator%( const Mod& n0 , const Mod& n1 ) { return n0 % n1.Represent(); } template Mod Inverse( const Mod& n ) { auto n_copy = n; n_copy.Invert(); return n_copy; } template Mod Power( const Mod& n , const INT_TYPE_FOR_MOD& p , const string& method ) { if( p >= 0 ){ return Power,INT_TYPE_FOR_MOD>( n , p , 1 , true , true , method ); } return Inverse( Power( n , -p , method ) ); } template <> inline Mod<2> Power( const Mod<2>& n , const INT_TYPE_FOR_MOD& p , const string& method ) { return p == 0 ? 1 : n; } template inline Mod Power( const Mod& n , const Mod& p , const string& method ) { return Power,INT_TYPE_FOR_MOD>( n , p.Represent() , method ); } template <> inline Mod<2> Power( const Mod<2>& n , const Mod<2>& p , const string& method ) { return p == 0 ? 1 : n; } template <> inline Mod<2> Square >( const Mod<2>& t ) { return t; } template inline string to_string( const Mod& n ) noexcept { return to_string( n.Represent() ) + " + MZ"; } void LazyEvaluationOfModularInverse( const INT_TYPE_FOR_MOD& M , const INT_TYPE_FOR_MOD& n , INT_TYPE_FOR_MOD& m ) { static VLArray memory_M{}; // vectorでなくVLArrayだと引数が小さい順に呼び出した時の計算量がO(1)からO(n)に跳ね上がってしまう。 static VLArray > memory_inverse{}; auto itr_M = memory_M.begin() , end_M = memory_M.end(); auto itr_inverse = memory_inverse.begin(); vector* p_inverse = nullptr; while( itr_M != end_M && p_inverse == nullptr ){ if( *itr_M == M ){ p_inverse = &( *itr_inverse ); } itr_M++; itr_inverse++; } if( p_inverse == nullptr ){ memory_M.push_front( M ); memory_inverse.push_front( vector() ); p_inverse = &( memory_inverse.front() ); p_inverse->push_back( M ); } const INT_TYPE_FOR_MOD size = p_inverse->size(); for( INT_TYPE_FOR_MOD i = size ; i <= n ; i++ ){ p_inverse->push_back( 0 ); } INT_TYPE_FOR_MOD& n_inv = ( *p_inverse )[n]; if( n_inv != 0 ){ m = n_inv; return; } const INT_TYPE_FOR_MOD M_abs = M >= 0 ? M : -M; const INT_TYPE_FOR_MOD n_sub = M_abs % n; INT_TYPE_FOR_MOD n_sub_inv = ( *p_inverse )[n_sub]; if( n_sub_inv == 0 ){ LazyEvaluationOfModularInverse( M , n_sub , n_sub_inv ); } if( n_sub_inv != M ){ n_inv = M_abs - ( ( n_sub_inv * ( M_abs / n ) ) % M_abs ); m = n_inv; return; } for( INT_TYPE_FOR_MOD i = 1 ; i < M_abs ; i++ ){ if( ( n * i ) % M_abs == 1 ){ n_inv = i; m = n_inv; return; } } n_inv = M; m = n_inv; return; } template inline constexpr const uint LimitOfPowerForFFT; template inline const T ( &PrimitiveRootOfTwoForFFT() noexcept )[LimitOfPowerForFFT]; template inline const T ( &InversePrimitiveRootOfTwoForFFT() noexcept )[LimitOfPowerForFFT]; template vector FFT( const vector& f , const uint& N ); template vector FFT( const vector& f , const uint& two_power , const uint& exponent ); template vector IFFT( const vector& f , const uint& N ); template vector IFFT( const vector& f , const uint& two_power , const T& two_power_inv , const uint& exponent ); template <> inline constexpr const uint LimitOfPowerForFFT > = 24; template <> inline const Mod<998244353> ( &PrimitiveRootOfTwoForFFT() noexcept )[LimitOfPowerForFFT >] { static const Mod<998244353> PRT[ LimitOfPowerForFFT > ] = { Mod<998244353>( 1 ) , Mod<998244353>( 998244352 ) , Mod<998244353>( 911660635 ) , Mod<998244353>( 625715529 ) , Mod<998244353>( 373294451 ) , Mod<998244353>( 827987769 ) , Mod<998244353>( 280333251 ) , Mod<998244353>( 581015842 ) , Mod<998244353>( 628092333 ) , Mod<998244353>( 300892551 ) , Mod<998244353>( 586046298 ) , Mod<998244353>( 615001099 ) , Mod<998244353>( 318017948 ) , Mod<998244353>( 64341522 ) , Mod<998244353>( 106061068 ) , Mod<998244353>( 304605202 ) , Mod<998244353>( 631920086 ) , Mod<998244353>( 857779016 ) , Mod<998244353>( 841431251 ) , Mod<998244353>( 805775211 ) , Mod<998244353>( 390359979 ) , Mod<998244353>( 923521 ) , Mod<998244353>( 961 ) , Mod<998244353>( 31 ) }; return PRT; } template <> inline const Mod<998244353> ( &InversePrimitiveRootOfTwoForFFT() noexcept )[LimitOfPowerForFFT >] { static const Mod<998244353> PRT[ LimitOfPowerForFFT > ] = { Mod<998244353>( 1 ) , Mod<998244353>( 998244352 ) , Mod<998244353>( 86583718 ) , Mod<998244353>( 488723995 ) , Mod<998244353>( 369330050 ) , Mod<998244353>( 543653592 ) , Mod<998244353>( 382946991 ) , Mod<998244353>( 844956623 ) , Mod<998244353>( 91420391 ) , Mod<998244353>( 433414612 ) , Mod<998244353>( 288894979 ) , Mod<998244353>( 260490556 ) , Mod<998244353>( 857007890 ) , Mod<998244353>( 736054570 ) , Mod<998244353>( 474649464 ) , Mod<998244353>( 948509906 ) , Mod<998244353>( 114942468 ) , Mod<998244353>( 962405921 ) , Mod<998244353>( 667573957 ) , Mod<998244353>( 46809892 ) , Mod<998244353>( 304321983 ) , Mod<998244353>( 30429817 ) , Mod<998244353>( 293967900 ) , Mod<998244353>( 128805723 ) }; return PRT; } template static vector FFT_Body( const vector& f , const uint& two_power , const uint& exponent , const uint& start , const uint& depth , const T ( &PRT )[LimitOfPowerForFFT] ); template vector FFT( const vector& f , const uint& N ) { uint two_power = 1; uint exponent = 0; while( N > two_power ){ two_power *= 2; exponent++; } return FFT( f , two_power , exponent ); } template vector FFT( const vector& f , const uint& two_power , const uint& exponent ) { const uint size = f.size(); if( size == two_power ){ return FFT_Body( f , two_power , exponent , 0 , 1 , PrimitiveRootOfTwoForFFT() ); } vector f_copy = f; const T zero{}; for( uint i = size ; i < two_power ; i++ ){ f_copy.push_back( zero ); } return FFT_Body( f_copy , two_power , exponent , 0 , 1 , PrimitiveRootOfTwoForFFT() ); } template vector IFFT( const vector& f , const uint& N ) { uint two_power = 1; T two_power_inv{ 1 }; uint exponent = 0; while( N > two_power ){ two_power *= 2; two_power_inv /= 2; exponent++; } return IFFT( f , two_power , two_power_inv , exponent ); } template vector IFFT( const vector& f , const uint& two_power , const T& two_power_inv , const uint& exponent ) { vector answer; const uint size = f.size(); if( size == two_power ){ answer = move( FFT_Body( f , two_power , exponent , 0 , 1 , InversePrimitiveRootOfTwoForFFT() ) ); } else { vector f_copy = f; const T zero{}; for( uint i = size ; i < two_power ; i++ ){ f_copy.push_back( zero ); } answer = move( FFT_Body( f_copy , two_power , exponent , 0 , 1 , InversePrimitiveRootOfTwoForFFT() ) ); } for( uint i = 0 ; i < two_power ; i++ ){ answer[i] *= two_power_inv; } return answer; } template static vector FFT_Body( const vector& f , const uint& two_power , const uint& exponent , const uint& start , const uint& depth , const T ( &PRT )[LimitOfPowerForFFT] ) { vector answer( two_power ); if( two_power == 1 ){ answer[0] = ( start < f.size() ? f[ start ] : 0 ); return answer; } const uint two_power_sub = two_power / 2; const uint exponent_sub = exponent - 1; const uint depth_sub = depth * 2; vector answer_sub0{ move( FFT_Body( f , two_power_sub , exponent_sub , start , depth_sub , PRT ) ) }; vector answer_sub1{ move( FFT_Body( f , two_power_sub , exponent_sub , start + depth , depth_sub , PRT ) ) }; const T& zeta = PRT[exponent]; T zeta_power{ 1 }; for( uint i = 0 ; i < two_power ; i++ ){ const uint i_sub = i % two_power_sub; answer[i] = answer_sub0[i_sub] + zeta_power * answer_sub1[i_sub]; zeta_power *= zeta; } return answer; } template class Polynomial { protected: vector m_f; // m_fのsize uint m_size; bool m_no_redundant_zero; public: inline Polynomial(); inline Polynomial( const T& t ); inline Polynomial( const Polynomial& f ); inline Polynomial( const uint& i , const T& t ); Polynomial& operator=( const T& t ); Polynomial& operator=( const Polynomial& f ); inline const T& operator[]( const uint& i ) const; inline T& operator[]( const uint& i ); inline Polynomial& operator+=( const T& t ); Polynomial& operator+=( const Polynomial& f ); inline Polynomial& operator-=( const T& t ); Polynomial& operator-=( const Polynomial& f ); Polynomial& operator*=( const T& t ); Polynomial& operator*=( const Polynomial& f ); Polynomial& operator/=( const T& t ); Polynomial& operator%=( const T& t ); inline Polynomial operator-() const; inline const vector& GetCoefficient() const noexcept; inline const uint& size() const noexcept; void RemoveRedundantZero(); inline string Display() const noexcept; static inline const Polynomial& zero(); static inline const T& const_zero(); static inline const T& const_one(); }; template bool operator==( const Polynomial& f0 , const T& t1 ); template bool operator==( const Polynomial& f0 , const Polynomial& f1 ); template inline bool operator!=( const Polynomial& f0 , const P& f1 ); template inline Polynomial operator+( const Polynomial& f0 , const P& f1 ); template inline Polynomial operator-( const Polynomial& f ); template inline Polynomial operator-( const Polynomial& f0 , const P& f1 ); template inline Polynomial operator*( const Polynomial& f0 , const P& f1 ); template inline Polynomial operator/( const Polynomial& f0 , const T& t1 ); template inline Polynomial operator%( const Polynomial& f0 , const T& t1 ); template inline Polynomial::Polynomial() : m_f() , m_size( 0 ) , m_no_redundant_zero( true ) {} template inline Polynomial::Polynomial( const T& t ) : Polynomial() { if( t != const_zero() ){ operator[]( 0 ) = t; } } template inline Polynomial::Polynomial( const Polynomial& f ) : m_f( f.m_f ) , m_size( f.m_size ) , m_no_redundant_zero( f.m_no_redundant_zero ) {} template inline Polynomial::Polynomial( const uint& i , const T& t ) : Polynomial() { if( t != const_zero() ){ operator[]( i ) = t; } } template inline Polynomial& Polynomial::operator=( const T& t ) { m_f.clear(); m_size = 0; operator[]( 0 ) = t; return *this; } template inline Polynomial& Polynomial::operator=( const Polynomial& f ) { m_f = f.m_f; m_size = f.m_size; m_no_redundant_zero = f.m_no_redundant_zero; return *this; } template const T& Polynomial::operator[]( const uint& i ) const { if( m_size <= i ){ return const_zero(); } return m_f[i]; } template inline T& Polynomial::operator[]( const uint& i ) { m_no_redundant_zero = false; const T& z = const_zero(); while( m_size <= i ){ m_f.push_back( z ); m_size++; } return m_f[i]; } template inline Polynomial& Polynomial::operator+=( const T& t ) { operator[]( 0 ) += t; return *this; } template Polynomial& Polynomial::operator+=( const Polynomial& f ) { for( uint i = 0 ; i < f.m_size ; i++ ){ operator[]( i ) += f.m_f[i]; } return *this; } template inline Polynomial& Polynomial::operator-=( const T& t ) { operator[]( 0 ) -= t; return *this; } template Polynomial& Polynomial::operator-=( const Polynomial& f ) { for( uint i = 0 ; i < f.m_size ; i++ ){ operator[]( i ) -= f.m_f[i]; } return *this; } template Polynomial& Polynomial::operator*=( const T& t ) { if( ! m_no_redundant_zero ){ RemoveRedundantZero(); } if( m_size == 0 || t == const_one() ){ return *this; } if( t == const_zero() ){ return operator=( zero() ); } for( uint i = 0 ; i < m_size ; i++ ){ operator[]( i ) *= t; } // Tが体である場合は省略可能 RemoveRedundantZero(); return *this; } template Polynomial& Polynomial::operator*=( const Polynomial& f ) { if( ! m_no_redundant_zero ){ RemoveRedundantZero(); } if( m_size == 0 ){ return *this; } if( f.m_size == 0 ){ return operator=( zero() ); } const uint size = m_size + f.m_size - 1; Polynomial product{}; for( uint i = 0 ; i < size ; i++ ){ T& product_i = product[i]; const uint j_min = m_size <= i ? i - m_size + 1 : 0; const uint j_lim = i < f.m_size ? i + 1 : f.m_size; for( uint j = j_min ; j < j_lim ; j++ ){ product_i += m_f[i - j] * f.m_f[j]; } } product.RemoveRedundantZero(); return operator=( product ); } template Polynomial& Polynomial::operator/=( const T& t ) { if( ! m_no_redundant_zero ){ RemoveRedundantZero(); } for( uint i = 0 ; i < m_size ; i++ ){ operator[]( i ) /= t; } // Tが体である場合は省略可能 RemoveRedundantZero(); return *this; } template Polynomial& Polynomial::operator%=( const T& t ) { if( ! m_no_redundant_zero ){ RemoveRedundantZero(); } for( uint i = 0 ; i < m_size ; i++ ){ operator[]( i ) %= t; } RemoveRedundantZero(); return *this; } template inline Polynomial Polynomial::operator-() const { Polynomial().operator-=( *this ); } template inline const vector& Polynomial::GetCoefficient() const noexcept { return m_f; } template inline const uint& Polynomial::size() const noexcept { return m_size; } template void Polynomial::RemoveRedundantZero() { if( m_no_redundant_zero ){ return; } const T& z = const_zero(); while( m_size > 0 ? m_f[m_size - 1] == z : false ){ m_f.pop_back(); m_size--; } m_no_redundant_zero = true; return; } template string Polynomial::Display() const noexcept { string s = "("; if( m_size > 0 ){ s += to_string( m_f[0] ); for( uint i = 1 ; i < m_size ; i++ ){ s += "," + to_string( m_f[i] ); } } s += ")"; return s; } template inline const Polynomial& Polynomial::zero() { static const Polynomial z{}; return z; } template inline const T& Polynomial::const_zero() { static const T z{ 0 }; return z; } template inline const T& Polynomial::const_one() { static const T o{ 1 }; return o; } template bool operator==( const Polynomial& f0 , const T& t1 ) { const uint& size = f0.size(); const T& zero = Polynomial::const_zero(); for( uint i = 1 ; i < size ; i++ ){ if( f0[i] != zero ){ return false; } } return f0[0] == t1; } template bool operator==( const Polynomial& f0 , const Polynomial& f1 ) { const uint& size0 = f0.size(); const uint& size1 = f1.size(); const uint& size = size0 < size1 ? size1 : size0; for( uint i = 0 ; i < size ; i++ ){ if( f0[i] != f1[i] ){ return false; } } return true; } template inline bool operator!=( const Polynomial& f0 , const P& f1 ) { return !( f0 == f1 ); } template inline Polynomial operator+( const Polynomial& f0 , const P& f1 ) { Polynomial f = f0; f += f1; return f; } template inline Polynomial operator-( const Polynomial& f ) { return Polynomial::zero() - f; } template inline Polynomial operator-( const Polynomial& f0 , const P& f1 ) { Polynomial f = f0; return f.operator-=( f1 ); } template inline Polynomial operator*( const Polynomial& f0 , const P& f1 ) { Polynomial f = f0; return f.operator*=( f1 ); } template inline Polynomial operator/( const Polynomial& f0 , const T& t1 ) { Polynomial f = f0; return f.operator/=( t1 ); } template inline Polynomial operator%( const Polynomial& f0 , const T& t1 ) { Polynomial f = f0; return f.operator%=( t1 ); } #define DEFINITION_OF_PARTIAL_SPECIALISATION_OF_MULTIPLICATION_OF_TRUNCATED_POLYNOMIAL( TYPE ) \ template <> inline TruncatedPolynomial< TYPE >& TruncatedPolynomial< TYPE >::operator*=( const Polynomial< TYPE >& f ) { return TruncatedPolynomial< TYPE >::FFT_Multiplication( f ); } \ \ template class TruncatedPolynomial : public Polynomial { private: // m_N == 0でも動くが、その場合はm_size == 1の時にm_size <= m_Nが成り立たなくなることに注意 uint m_N; public: inline TruncatedPolynomial( const uint& N = 0 ); inline TruncatedPolynomial( const TruncatedPolynomial& f ); inline TruncatedPolynomial( const uint& N , const T& t ); TruncatedPolynomial( const uint& N , const Polynomial& f ); inline TruncatedPolynomial( const uint& N , const uint& i , const T& t ); // m_Nも代入されることに注意 inline TruncatedPolynomial& operator=( const TruncatedPolynomial& f ); inline TruncatedPolynomial& operator=( const T& t ); inline TruncatedPolynomial& operator=( const Polynomial& f ); // m_Nは変化しないことに注意 inline TruncatedPolynomial& operator+=( const T& t ); TruncatedPolynomial& operator+=( const Polynomial& f ); inline TruncatedPolynomial& operator-=( const T& t ); TruncatedPolynomial& operator-=( const Polynomial& f ); inline TruncatedPolynomial& operator*=( const T& t ); TruncatedPolynomial& operator*=( const Polynomial& f ); inline TruncatedPolynomial& operator/=( const T& t ); inline TruncatedPolynomial& operator/=( const TruncatedPolynomial& t ); inline TruncatedPolynomial& operator%=( const T& t ); inline TruncatedPolynomial operator-() const; inline void SetTruncation( const uint& N ) noexcept; inline const uint& GetTruncation() const noexcept; private: inline void Truncate(); // m_N == 0の場合はサポート外 TruncatedPolynomial& FFT_Multiplication( const Polynomial& f ); }; template inline TruncatedPolynomial operator+( const TruncatedPolynomial& f0 , const P& f1 ); template inline TruncatedPolynomial operator-( const TruncatedPolynomial& f ); template inline TruncatedPolynomial operator-( const TruncatedPolynomial& f0 , const P& f1 ); template inline TruncatedPolynomial operator*( const TruncatedPolynomial& f0 , const P& f1 ); template inline TruncatedPolynomial operator/( const TruncatedPolynomial& f0 , const P& f1 ); template inline TruncatedPolynomial operator%( const TruncatedPolynomial& f0 , const T& t1 ); // m_Nが1下がることに注意 template TruncatedPolynomial Differential( const TruncatedPolynomial& f ); // m_Nがi下がることに注意 template inline TruncatedPolynomial Differential( const uint& i , const TruncatedPolynomial& f ); // m_Nが1上がることに注意 // Tが標数0またはf.m_N + 1以上の体の場合のみサポート template TruncatedPolynomial Integral( const TruncatedPolynomial& f ); // f[0]が可逆な場合のみサポート template TruncatedPolynomial Inverse( const TruncatedPolynomial& f ); // Tが標数0またはf.m_N以上の体でかつf[0] == 0の場合のみサポート template TruncatedPolynomial Exp( const TruncatedPolynomial& f ); // Tが標数0またはf.m_N以上の体でかつf[0] == 1の場合のみサポート template inline TruncatedPolynomial Log( const TruncatedPolynomial& f ); // Tが標数0またはf.m_N以上の体でかつf[0] == 1の場合のみサポート template TruncatedPolynomial Power( const TruncatedPolynomial& f , const T& t ); template inline TruncatedPolynomial::TruncatedPolynomial( const uint& N ) : Polynomial() , m_N( N ) {} template inline TruncatedPolynomial::TruncatedPolynomial( const TruncatedPolynomial& f ) : Polynomial( f ) , m_N( f.m_N ) {} template inline TruncatedPolynomial::TruncatedPolynomial( const uint& N , const T& t ) : Polynomial( t ) , m_N( N ) {} template TruncatedPolynomial::TruncatedPolynomial( const uint& N , const Polynomial& f ) : Polynomial() , m_N( N ) { const uint& f_size = f.Polynomial::size(); const uint& size = f_size < m_N ? f_size : m_N; for( uint i = 0 ; i < size ; i++ ){ Polynomial::m_f.push_back( f.Polynomial::operator[]( i ) ); Polynomial::m_size++; } } template inline TruncatedPolynomial::TruncatedPolynomial( const uint& N , const uint& i , const T& t ) : Polynomial() , m_N( N ) { if( i < m_N ? t != Polynomial::const_zero() : false ){ Polynomial::operator[]( i ) = t; } } template inline TruncatedPolynomial& TruncatedPolynomial::operator=( const TruncatedPolynomial& f ) { Polynomial::operator=( f ); m_N = f.m_N; return *this; } template inline TruncatedPolynomial& TruncatedPolynomial::operator=( const T& t ) { Polynomial::operator=( t ); return *this; } template inline TruncatedPolynomial& TruncatedPolynomial::operator=( const Polynomial& f ) { return operator=( TruncatedPolynomial( m_N , f ) ); } template inline TruncatedPolynomial& TruncatedPolynomial::operator+=( const T& t ) { Polynomial::operator+=( t ); return *this; } template TruncatedPolynomial& TruncatedPolynomial::operator+=( const Polynomial& f ) { const uint& f_size = f.Polynomial::size(); const uint& size = f_size < m_N ? f_size : m_N; for( uint i = 0 ; i < size ; i++ ){ Polynomial::operator[]( i ) += f.Polynomial::operator[]( i ); } return *this; } template inline TruncatedPolynomial& TruncatedPolynomial::operator-=( const T& t ) { Polynomial::operator-=( t ); return *this; } template TruncatedPolynomial& TruncatedPolynomial::operator-=( const Polynomial& f ) { const uint& f_size = f.Polynomial::size(); const uint& size = f_size < m_N ? f_size : m_N; for( uint i = 0 ; i < size ; i++ ){ Polynomial::operator[]( i ) -= f.Polynomial::operator[]( i ); } return *this; } template inline TruncatedPolynomial& TruncatedPolynomial::operator*=( const T& t ) { Polynomial::operator*=( t ); return *this; } template TruncatedPolynomial& TruncatedPolynomial::operator*=( const Polynomial& f ) { if( ! Polynomial::m_no_redundant_zero ){ Polynomial::RemoveRedundantZero(); } if( Polynomial::m_size == 0 ){ return *this; } const uint& f_size = f.Polynomial::size(); if( f_size == 0 ){ return operator=( Polynomial::zero() ); } uint size = Polynomial::m_size + f_size - 1; if( size >= m_N ){ size = m_N; } TruncatedPolynomial product{ m_N , 0 }; for( uint i = 0 ; i < size ; i++ ){ T& product_i = product[i]; const uint j_min = Polynomial::m_size <= i ? i - Polynomial::m_size + 1 : 0; const uint j_lim = i < f_size ? i + 1 : f_size; for( uint j = j_min ; j < j_lim ; j++ ){ product_i += Polynomial::operator[]( i - j ) * f.Polynomial::operator[]( j ); } } product.Polynomial::RemoveRedundantZero(); return operator=( product ); } DEFINITION_OF_PARTIAL_SPECIALISATION_OF_MULTIPLICATION_OF_TRUNCATED_POLYNOMIAL( Mod<998244353> ); template inline TruncatedPolynomial& TruncatedPolynomial::operator/=( const T& t ) { Polynomial::operator/=( t ); return *this; } template inline TruncatedPolynomial& TruncatedPolynomial::operator/=( const TruncatedPolynomial& f ) { return operator*=( Inverse( m_N == f.m_N ? f : TruncatedPolynomial( m_N , f ) ) ); } template inline TruncatedPolynomial& TruncatedPolynomial::operator%=( const T& t ) { Polynomial::operator%=( t ); return *this; } template inline TruncatedPolynomial TruncatedPolynomial::operator-() const { return TruncatedPolynomial( m_N ).operator-=( *this ); } template inline void TruncatedPolynomial::SetTruncation( const uint& N ) noexcept { m_N = N; Truncate(); } template inline const uint& TruncatedPolynomial::GetTruncation() const noexcept { return m_N; } template inline void TruncatedPolynomial::Truncate(){ while( Polynomial::m_size > m_N ){ Polynomial::m_f.pop_back(); Polynomial::m_size--; } } template TruncatedPolynomial& TruncatedPolynomial::FFT_Multiplication( const Polynomial& f ) { const uint N = m_N * 2 - 1; uint two_power = 1; T two_power_inv{ 1 }; uint exponent = 0; while( N > two_power ){ two_power *= 2; two_power_inv /= 2; exponent++; } vector f0{ move( FFT( Polynomial::m_f , two_power , exponent ) ) }; const uint& size = f.Polynomial::size(); const vector& f_m_f = f.Polynomial::GetCoefficient(); vector f1; if( size <= m_N ){ f1 = move( FFT( f_m_f , two_power , exponent ) ); } else { for( uint i = 0 ; i < m_N ; i++ ){ f1.push_back( f_m_f[i] ); } f1 = move( FFT( f1 , two_power , exponent ) ); } for( uint i = 0 ; i < two_power ; i++ ){ f0[i] *= f1[i]; } Polynomial::m_f = move( IFFT( f0 , two_power , two_power_inv , exponent ) ); for( uint i = m_N ; i < two_power ; i++ ){ Polynomial::m_f.pop_back(); } Polynomial::m_size = m_N; return *this; } template inline TruncatedPolynomial operator+( const TruncatedPolynomial& f0 , const P& f1 ) { TruncatedPolynomial f = f0; f += f1; return f; } template inline TruncatedPolynomial operator-( const TruncatedPolynomial& f ) { return TruncatedPolynomial::zero() - f; } template inline TruncatedPolynomial operator-( const TruncatedPolynomial& f0 , const P& f1 ) { TruncatedPolynomial f = f0; return f.operator-=( f1 ); } template inline TruncatedPolynomial operator*( const TruncatedPolynomial& f0 , const P& f1 ) { TruncatedPolynomial f = f0; return f.operator*=( f1 ); } template inline TruncatedPolynomial operator/( const TruncatedPolynomial& f0 , const P& f1 ) { TruncatedPolynomial f = f0; return f.operator/=( f1 ); } template inline TruncatedPolynomial operator%( const TruncatedPolynomial& f0 , const T& t1 ) { TruncatedPolynomial f = f0; return f.operator%=( t1 ); } template TruncatedPolynomial Differential( const TruncatedPolynomial& f ) { const uint& N = f.GetTruncation(); if( N == 0 ){ return TruncatedPolynomial(); } TruncatedPolynomial f_dif{ N - 1 }; const uint& size = f.size(); for( uint i = 1 ; i < size ; i++ ){ f_dif[i - 1] = i * f[i]; } return f_dif; } template inline TruncatedPolynomial Differential( const uint& i , const TruncatedPolynomial& f ) { return i == 0 ? f : Differential( i - 1 , Differential( f ) ); } template TruncatedPolynomial Integral( const TruncatedPolynomial& f ) { const uint& N = f.GetTruncation(); TruncatedPolynomial f_int{ N + 1 }; const uint& size = f.size(); for( uint i = 1 ; i <= size ; i++ ){ f_int[i] = f[i - 1] / T( i ); } return f_int; } template TruncatedPolynomial Inverse( const TruncatedPolynomial& f ) { const uint& N = f.GetTruncation(); const T& one = Polynomial::const_one(); const T two = one + one; uint power = 1; TruncatedPolynomial f_inv{ power , one / f[0] }; while( power < N ){ power *= 2; f_inv.SetTruncation( power ); f_inv *= - f_inv * f + two; } f_inv.SetTruncation( N ); return f_inv; } template TruncatedPolynomial Exp( const TruncatedPolynomial& f ) { const uint& N = f.GetTruncation(); const T& one = Polynomial::const_one(); uint power = 1; TruncatedPolynomial f_exp{ power , one }; while( power < N ){ power *= 2; f_exp.SetTruncation( power ); f_exp *= - Log( f_exp ) + f + one; } f_exp.SetTruncation( N ); return f_exp; } template inline TruncatedPolynomial Log( const TruncatedPolynomial& f ) { return Integral( Differential( f ) / f ); } template inline TruncatedPolynomial Power( const TruncatedPolynomial& f , const T& t ) { return Exp( Log( f ) * t ); } constexpr const ll P = 998244353; constexpr const ll Q = 999630629; using MOD = Mod

; int main(){ UNTIE; CIN( ll , N ); ll A[100000]; ll sum = 0; FOR( i , 0 , N ){ ll& Ai = A[i]; cin >> Ai; sum += Ai; } MOD coef{}; MOD one = MOD( 1 ); ll D_signed = sum - Q + 1; if( D_signed > 0 ){ sort( A , A + N ); uint B[100000]; ll count[100000]; ll Ai_prev = 0; ll num = -1; FOR( i , 0 , N ){ ll& Ai = A[i]; if( Ai_prev == Ai ){ count[num]++; } else if( Ai < D_signed ){ num++; B[num] = uint( Ai ); count[num] = 1; Ai_prev = Ai; } else { i = N; } } uint D = uint( D_signed ); TruncatedPolynomial f{ D }; num++; FOR( i , 0 , num ){ uint& Bi = B[i]; MOD count_i{ count[i] }; uint j_lim = ( D - 1 ) / Bi + 1; uint d = 0; FOR( j , 1 , j_lim ){ d += Bi; if( j % 2 == 0 ){ f[d] -= count_i / j; } else { f[d] += count_i / j; } } } f = Exp( f ); FOR( i , 0 , D ){ coef += f[i]; } } MOD m{ one }; MOD power{ 2 }; N--; while( N != 0 ){ if( N % 2 == 1 ){ m *= power; } power = power * power; N /= 2; } RETURN( ( m * sum - coef * Q ).Represent() ); }