結果
問題 | No.2130 分配方法の数え上げ mod 998244353 |
ユーザー | 👑 p-adic |
提出日時 | 2023-01-01 19:01:41 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 5 ms / 2,000 ms |
コード長 | 16,526 bytes |
コンパイル時間 | 2,156 ms |
コンパイル使用メモリ | 204,228 KB |
実行使用メモリ | 6,824 KB |
最終ジャッジ日時 | 2024-11-27 00:12:43 |
合計ジャッジ時間 | 3,368 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge3 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
6,820 KB |
testcase_01 | AC | 2 ms
6,824 KB |
testcase_02 | AC | 1 ms
6,820 KB |
testcase_03 | AC | 2 ms
6,816 KB |
testcase_04 | AC | 2 ms
6,816 KB |
testcase_05 | AC | 1 ms
6,816 KB |
testcase_06 | AC | 2 ms
6,816 KB |
testcase_07 | AC | 1 ms
6,816 KB |
testcase_08 | AC | 2 ms
6,816 KB |
testcase_09 | AC | 2 ms
6,816 KB |
testcase_10 | AC | 1 ms
6,816 KB |
testcase_11 | AC | 2 ms
6,816 KB |
testcase_12 | AC | 2 ms
6,820 KB |
testcase_13 | AC | 1 ms
6,820 KB |
testcase_14 | AC | 1 ms
6,820 KB |
testcase_15 | AC | 2 ms
6,820 KB |
testcase_16 | AC | 2 ms
6,816 KB |
testcase_17 | AC | 2 ms
6,816 KB |
testcase_18 | AC | 2 ms
6,816 KB |
testcase_19 | AC | 2 ms
6,816 KB |
testcase_20 | AC | 2 ms
6,816 KB |
testcase_21 | AC | 2 ms
6,824 KB |
testcase_22 | AC | 2 ms
6,820 KB |
testcase_23 | AC | 2 ms
6,820 KB |
testcase_24 | AC | 2 ms
6,816 KB |
testcase_25 | AC | 2 ms
6,816 KB |
testcase_26 | AC | 2 ms
6,816 KB |
testcase_27 | AC | 5 ms
6,816 KB |
testcase_28 | AC | 2 ms
6,816 KB |
testcase_29 | AC | 5 ms
6,816 KB |
testcase_30 | AC | 1 ms
6,820 KB |
testcase_31 | AC | 2 ms
6,816 KB |
testcase_32 | AC | 1 ms
6,820 KB |
testcase_33 | AC | 2 ms
6,816 KB |
testcase_34 | AC | 2 ms
6,816 KB |
testcase_35 | AC | 2 ms
6,816 KB |
testcase_36 | AC | 1 ms
6,816 KB |
testcase_37 | AC | 1 ms
6,816 KB |
ソースコード
// 手持ちのMod<998244353>のライブラリがバグってしまったのでデバッグ用提出。 #include <bits/stdc++.h> using namespace std; using ll = long long; #define TYPE_OF( VAR ) decay_t<decltype( VAR )> #define UNTIE ios_base::sync_with_stdio( false ); cin.tie( nullptr ) #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 FOREQ( VAR , INITIAL , FINAL ) for( TYPE_OF( FINAL ) VAR = INITIAL ; VAR <= FINAL ; VAR ++ ) #define FOREQINV( VAR , INITIAL , FINAL ) for( TYPE_OF( INITIAL ) VAR = INITIAL ; VAR >= FINAL ; VAR -- ) #define FOR_ITR( ARRAY , ITR , END ) for( auto ITR = ARRAY .begin() , END = ARRAY .end() ; ITR != END ; ITR ++ ) #define REPEAT( HOW_MANY_TIMES ) FOR( VARIABLE_FOR_REPEAT , 0 , HOW_MANY_TIMES ) #define COUT( ANSWER ) cout << ( ANSWER ) << "\n"; #define QUIT return 0 #define RETURN( ANSWER ) COUT( ANSWER ); QUIT #define POWER( ANSWER , VAR , EXPONENT_REF , MODULO ) \ TYPE_OF( VAR ) ANSWER = 1; \ TYPE_OF( VAR ) VARIABLE_FOR_SQUARE_FOR_POWER = VAR; \ while( EXPONENT_REF != 0 ){ \ if( EXPONENT_REF % 2 == 1 ){ \ ANSWER = ( ANSWER * VARIABLE_FOR_SQUARE_FOR_POWER ) % MODULO; \ } \ VARIABLE_FOR_SQUARE_FOR_POWER = ( VARIABLE_FOR_SQUARE_FOR_POWER * VARIABLE_FOR_SQUARE_FOR_POWER ) % MODULO; \ EXPONENT_REF /= 2; \ } template <typename INT1 , typename INT2> inline INT1& Residue( INT1& n , const INT2& M ) noexcept { return n >= 0 ? n %= M : ( ( ( ( ++n ) *= -1 ) %= M ) *= -1 ) += M - 1; } template <typename INT1 , typename INT2> inline INT1 Residue( INT1&& n , const INT2& M ) noexcept { return move( Residue( n , M ) ); } template <typename INT1 , typename INT2> inline INT1 Residue( const INT1& n , const INT2& M ) noexcept { return Residue( move( INT1( n ) ) , M ); } #define SFINAE_TYPE_FOR_MOD( TYPE ) \ decltype( INT_TYPE_FOR_MOD( decay_t<T>() ) , TYPE() ) \ #define DECLARATION_OF_COMPARISON_FOR_MOD( FUNC ) \ inline bool operator FUNC( const Mod<M>& n ) const noexcept \ #define DECLARATION_OF_ARITHMETIC_FOR_MOD( FUNC ) \ inline Mod<M> operator FUNC( const Mod<M>& n ) const noexcept; \ template <typename T> inline SFINAE_TYPE_FOR_MOD( Mod<M> ) operator FUNC( T&& n ) const noexcept; \ #define DEFINITION_OF_COMPARISON_FOR_MOD( FUNC ) \ template <INT_TYPE_FOR_MOD M> inline bool Mod<M>::operator FUNC( const Mod<M>& n ) const noexcept { return m_n FUNC n.m_n; } \ #define DEFINITION_OF_ARITHMETIC_FOR_MOD( FUNC , FORMULA ) \ template <INT_TYPE_FOR_MOD M> inline Mod<M> Mod<M>::operator FUNC( const Mod<M>& n ) const noexcept { return move( Mod<M>( *this ) FUNC ## = n ); } \ template <INT_TYPE_FOR_MOD M> template <typename T> inline SFINAE_TYPE_FOR_MOD( Mod<M> ) Mod<M>::operator FUNC( T&& n ) const noexcept { return FORMULA; } \ template <INT_TYPE_FOR_MOD M , typename T> inline SFINAE_TYPE_FOR_MOD( Mod<M> ) operator FUNC( T&& n0 , const Mod<M>& n1 ) noexcept { return move( Mod<M>( forward<T>( n0 ) ) FUNC ## = n1 ); } \ template <typename T> using VLArray = list<T>; using INT_TYPE_FOR_MOD = int; // using INT_TYPE_FOR_MOD = ll; // ここをtempate <typename INT , INT M>などにしてしまうとoperator+などを呼び出す際に型推論に失敗する。整数型を変えたい時はINT_TYPE_FOR_MODの型エイリアスを変更する。 template <INT_TYPE_FOR_MOD M> class Mod { protected: INT_TYPE_FOR_MOD m_n; public: inline Mod() noexcept; inline Mod( const Mod<M>& n ) noexcept; inline Mod( Mod<M>& n ) noexcept; // INT_TYPE_FOR_MODがintならば恐らく実行速度に影響しないが念のため。 inline Mod( Mod<M>&& n ) noexcept; template <typename T> inline Mod( T& n , SFINAE_TYPE_FOR_MOD( int ) dummy = 0 ) noexcept; template <typename T> inline Mod( T&& n , SFINAE_TYPE_FOR_MOD( int ) dummy = 0 ) noexcept; inline Mod<M>& operator=( const Mod<M>& n ) noexcept; inline Mod<M>& operator+=( const Mod<M>& n ) noexcept; inline Mod<M>& operator-=( const Mod<M>& n ) noexcept; inline Mod<M>& operator*=( const Mod<M>& n ) noexcept; inline Mod<M>& operator/=( const Mod<M>& n ); inline Mod<M>& operator++() noexcept; inline Mod<M> operator++( int ) noexcept; inline Mod<M>& operator--() noexcept; inline Mod<M> operator--( int ) noexcept; DECLARATION_OF_COMPARISON_FOR_MOD( == ); DECLARATION_OF_COMPARISON_FOR_MOD( != ); DECLARATION_OF_COMPARISON_FOR_MOD( < ); DECLARATION_OF_COMPARISON_FOR_MOD( <= ); DECLARATION_OF_COMPARISON_FOR_MOD( > ); DECLARATION_OF_COMPARISON_FOR_MOD( >= ); DECLARATION_OF_ARITHMETIC_FOR_MOD( + ); DECLARATION_OF_ARITHMETIC_FOR_MOD( - ); DECLARATION_OF_ARITHMETIC_FOR_MOD( * ); DECLARATION_OF_ARITHMETIC_FOR_MOD( / ); inline Mod<M> operator-() const noexcept; inline Mod<M>& SignInvert() noexcept; // Mが素数である場合のみサポート。 inline Mod<M>& Invert(); template <typename T> inline Mod<M>& PositivePower( T&& exponent ) noexcept; // Mが素数であるかexponent>=0である場合にのみサポート。 template <typename T> inline Mod<M>& Power( T&& exponent ); inline const INT_TYPE_FOR_MOD& Represent() const noexcept; inline void swap( Mod<M>& n ) noexcept; // Mが素数かつn < g_memory_lengthである場合のみサポート。 static inline const INT_TYPE_FOR_MOD& Inverse( const INT_TYPE_FOR_MOD& n ) noexcept; // n < g_memory_lengthである場合のみサポート。 static inline const INT_TYPE_FOR_MOD& Factorial( const INT_TYPE_FOR_MOD& n ) noexcept; // Mが素数かつn < g_memory_lengthである場合のみサポート。 static inline const INT_TYPE_FOR_MOD& FactorialInverse( const INT_TYPE_FOR_MOD& n ) noexcept; static inline const Mod<M>& zero() noexcept; static inline const Mod<M>& one() noexcept; private: static inline constexpr int BinaryDigitUpperBound() noexcept; static inline constexpr ll MontgomeryBasePower( INT_TYPE_FOR_MOD&& exponent ) noexcept; static constexpr const int g_Montgomery_digit = BinaryDigitUpperBound(); static constexpr const ll g_Montgomery_base = ll( 1 ) << g_Montgomery_digit; static constexpr const ll g_Montgomery_base_minus = g_Montgomery_base - 1; static constexpr const ll g_Montgomery_M_negative_inverse = g_Montgomery_base - MontgomeryBasePower( ( 1 << ( g_Montgomery_digit - 1 ) ) - 1 ); static constexpr const ll g_Montgomery_base_square = ( g_Montgomery_base * g_Montgomery_base ) % M; static constexpr const INT_TYPE_FOR_MOD g_memory_bound = 1000000; static constexpr const INT_TYPE_FOR_MOD g_memory_length = M < g_memory_bound ? M : g_memory_bound; static inline ll MontgomeryTranformation( const INT_TYPE_FOR_MOD& n ) noexcept; static inline ll& MontgomeryReduction( ll& n ) noexcept; static inline INT_TYPE_FOR_MOD MontgomeryMultiplication( const INT_TYPE_FOR_MOD& n0 , const INT_TYPE_FOR_MOD& n1 ) noexcept; static inline void Normalise( INT_TYPE_FOR_MOD& n ) noexcept; }; // Mが素数である場合にのみサポート。 template <INT_TYPE_FOR_MOD M> Mod<M> inline Inverse( const Mod<M>& n ); // Mが素数であるかexponent>=0である場合にのみサポート。 template <INT_TYPE_FOR_MOD M , typename T> inline Mod<M> Power( const Mod<M>& n , const T& exponent ); template <typename T> inline Mod<2> Power( const Mod<2>& n , const T& p ); // ../Power/a_Body.hppにて定義。 template <typename T> inline T Square( const T& t ); template <> inline Mod<2> Square<Mod<2> >( const Mod<2>& t ); template <INT_TYPE_FOR_MOD M> inline void swap( Mod<M>& n0 , Mod<M>& n1 ) noexcept; template <INT_TYPE_FOR_MOD M> inline string to_string( const Mod<M>& n ) noexcept; template<INT_TYPE_FOR_MOD M , class Traits> inline basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os , const Mod<M>& n ); template <INT_TYPE_FOR_MOD M> inline constexpr int Mod<M>::BinaryDigitUpperBound() noexcept { int answer = 0; ll power = 1; while( M > power ){ answer++; power <<= 1; } return answer; } template <INT_TYPE_FOR_MOD M> inline constexpr ll Mod<M>::MontgomeryBasePower( INT_TYPE_FOR_MOD&& exponent ) noexcept { ll prod = 1; ll power = M; while( exponent != 0 ){ if( ( exponent & 1 ) == 1 ){ ( prod *= power ) &= g_Montgomery_base_minus; } ( power *= power ) &= g_Montgomery_base_minus; exponent >>= 1; } return prod; } template <INT_TYPE_FOR_MOD M> inline ll Mod<M>::MontgomeryTranformation( const INT_TYPE_FOR_MOD& n ) noexcept { ll n_copy = n; return move( MontgomeryReduction( n_copy *= g_Montgomery_base_square ) ); } template <INT_TYPE_FOR_MOD M> inline ll& Mod<M>::MontgomeryReduction( ll& n ) noexcept { ll n_copy = n; return ( ( n += ( ( ( n_copy &= g_Montgomery_base_minus ) *= g_Montgomery_M_negative_inverse ) &= g_Montgomery_base_minus ) *= M ) >>= g_Montgomery_digit ) < M ? n : n -= M; } template <INT_TYPE_FOR_MOD M> inline INT_TYPE_FOR_MOD Mod<M>::MontgomeryMultiplication( const INT_TYPE_FOR_MOD& n0 , const INT_TYPE_FOR_MOD& n1 ) noexcept { ll n0_copy = n0; return MontgomeryReduction( MontgomeryReduction( n0_copy *= n1 ) *= g_Montgomery_base_square ); } template <INT_TYPE_FOR_MOD M> inline void Mod<M>::Normalise( INT_TYPE_FOR_MOD& n ) noexcept { if( n >= M ){ n -= M; } else if( n < 0 ){ n += M; } } template <INT_TYPE_FOR_MOD M> inline Mod<M>::Mod() noexcept : m_n() {} template <INT_TYPE_FOR_MOD M> inline Mod<M>::Mod( const Mod<M>& n ) noexcept : m_n( n.m_n ) {} template <INT_TYPE_FOR_MOD M> inline Mod<M>::Mod( Mod<M>& n ) noexcept : m_n( n.m_n ) {} template <INT_TYPE_FOR_MOD M> inline Mod<M>::Mod( Mod<M>&& n ) noexcept : m_n( move( n.m_n ) ) {} // nの書き換えを防ぐために明示的にキャスト template <INT_TYPE_FOR_MOD M> template<typename T> inline Mod<M>::Mod( T& n , SFINAE_TYPE_FOR_MOD( int ) dummy ) noexcept : m_n( Residue( decay_t<T>( n ) , M ) ) {} template <INT_TYPE_FOR_MOD M> template<typename T> inline Mod<M>::Mod( T&& n , SFINAE_TYPE_FOR_MOD( int ) dummy ) noexcept : m_n( Residue( forward<T>( n ) , M ) ) {} template <INT_TYPE_FOR_MOD M> inline Mod<M>& Mod<M>::operator=( const Mod<M>& n ) noexcept { m_n = n.m_n; return *this; } template <INT_TYPE_FOR_MOD M> inline Mod<M>& Mod<M>::operator+=( const Mod<M>& n ) noexcept { Normalise( m_n += n.m_n ); return *this; } template <INT_TYPE_FOR_MOD M> inline Mod<M>& Mod<M>::operator-=( const Mod<M>& n ) noexcept { Normalise( m_n -= n.m_n ); return *this; } template <INT_TYPE_FOR_MOD M> inline Mod<M>& Mod<M>::operator*=( const Mod<M>& n ) noexcept { m_n = MontgomeryMultiplication( m_n , n.m_n ); return *this; } template <INT_TYPE_FOR_MOD M> inline Mod<M>& Mod<M>::operator/=( const Mod<M>& n ) { return operator*=( Mod<M>( n ).Invert() ); } template <INT_TYPE_FOR_MOD M> inline Mod<M>& Mod<M>::operator++() noexcept { return operator+=( one() ); } template <INT_TYPE_FOR_MOD M> inline Mod<M> Mod<M>::operator++( int ) noexcept { Mod<M> n{ *this }; operator++(); return n; } template <INT_TYPE_FOR_MOD M> inline Mod<M>& Mod<M>::operator--() noexcept { return operator-=( one() ); } template <INT_TYPE_FOR_MOD M> inline Mod<M> Mod<M>::operator--( int ) noexcept { Mod<M> n{ *this }; operator--(); return n; } DEFINITION_OF_COMPARISON_FOR_MOD( == ); DEFINITION_OF_COMPARISON_FOR_MOD( != ); DEFINITION_OF_COMPARISON_FOR_MOD( > ); DEFINITION_OF_COMPARISON_FOR_MOD( >= ); DEFINITION_OF_COMPARISON_FOR_MOD( < ); DEFINITION_OF_COMPARISON_FOR_MOD( <= ); DEFINITION_OF_ARITHMETIC_FOR_MOD( + , Mod<M>( forward<T>( n ) ) += *this ); DEFINITION_OF_ARITHMETIC_FOR_MOD( - , Mod<M>( forward<T>( n ) ).SignInvert() += *this ); DEFINITION_OF_ARITHMETIC_FOR_MOD( * , Mod<M>( forward<T>( n ) ) *= *this ); DEFINITION_OF_ARITHMETIC_FOR_MOD( / , Mod<M>( forward<T>( n ) ).Invert() *= *this ); template <INT_TYPE_FOR_MOD M> inline Mod<M> Mod<M>::operator-() const noexcept { return move( Mod<M>( *this ).SignInvert() ); } template <INT_TYPE_FOR_MOD M> inline Mod<M>& Mod<M>::SignInvert() noexcept { if( m_n > 0 ){ m_n = M - m_n; } return *this; } template <INT_TYPE_FOR_MOD M> inline Mod<M>& Mod<M>::Invert() { assert( m_n > 0 ); if( m_n < g_memory_length ){ m_n = Inverse( m_n ); } else{ const INT_TYPE_FOR_MOD m_n_minus = M - m_n; if( m_n_minus < g_memory_length ){ m_n = M - Inverse( m_n_minus ); } else { return PositivePower( M - 2 ); } } return *this; } template <INT_TYPE_FOR_MOD M> template <typename T> inline Mod<M>& Mod<M>::PositivePower( T&& exponent ) noexcept { ll prod = g_Montgomery_base; ll power = MontgomeryTranformation( m_n ); while( exponent != 0 ){ if( ( exponent & 1 ) == 1 ){ MontgomeryReduction( prod *= power ); } MontgomeryReduction( power *= power ); exponent >>= 1; } m_n = INT_TYPE_FOR_MOD( MontgomeryReduction( prod ) ); return *this; } template <INT_TYPE_FOR_MOD M> template <typename T> inline Mod<M>& Mod<M>::Power( T&& exponent ) { if( exponent < 0 ){ assert( m_n != 0 ); exponent *= 2 - M; } exponent %= M - 1; if( exponent != 0 ){ return PositivePower( forward<T>( exponent ) ); } return *this; } template <INT_TYPE_FOR_MOD M> inline const INT_TYPE_FOR_MOD& Mod<M>::Inverse( const INT_TYPE_FOR_MOD& n ) noexcept { static INT_TYPE_FOR_MOD memory[g_memory_length] = { -1 , 1 }; static int length_curr = 2; while( length_curr <= n ){ memory[length_curr] = M - MontgomeryMultiplication( memory[M % length_curr] , M / length_curr ); length_curr++; } return memory[n]; } template <INT_TYPE_FOR_MOD M> inline const INT_TYPE_FOR_MOD& Mod<M>::Factorial( const INT_TYPE_FOR_MOD& n ) noexcept { static INT_TYPE_FOR_MOD memory[g_memory_length] = { 1 , 1 }; static int length_curr = 2; static ll val_curr = g_Montgomery_base; while( length_curr <= n ){ memory[length_curr] = INT_TYPE_FOR_MOD( MontgomeryReduction( val_curr *= MontgomeryTranformation( length_curr ) ) ); length_curr++; } return memory[n]; } template <INT_TYPE_FOR_MOD M> inline const INT_TYPE_FOR_MOD& Mod<M>::FactorialInverse( const INT_TYPE_FOR_MOD& n ) noexcept { static INT_TYPE_FOR_MOD memory[g_memory_length] = { 1 , 1 }; static int length_curr = 2; static ll val_curr = g_Montgomery_base; while( length_curr <= n ){ memory[length_curr] = INT_TYPE_FOR_MOD( MontgomeryReduction( val_curr *= MontgomeryTranformation( Inverse( length_curr ) ) ) ); length_curr++; } return memory[n]; } template <INT_TYPE_FOR_MOD M> inline const INT_TYPE_FOR_MOD& Mod<M>::Represent() const noexcept { return m_n; } template <INT_TYPE_FOR_MOD M> inline void Mod<M>::swap( Mod<M>& n ) noexcept { std::swap( m_n , n.m_n ); } template <INT_TYPE_FOR_MOD M> inline const Mod<M>& Mod<M>::zero() noexcept { static const Mod<M> z{}; return z; } template <INT_TYPE_FOR_MOD M> inline const Mod<M>& Mod<M>::one() noexcept { static const Mod<M> o{ 1 }; return o; } template <INT_TYPE_FOR_MOD M> inline Mod<M> Inverse( const Mod<M>& n ) { return move( Mod<M>( n ).Invert() ); } template <INT_TYPE_FOR_MOD M , typename T> inline Mod<M> Power( const Mod<M>& n , const T& exponent ) { return move( Mod<M>( n ).Power( T( exponent ) ) ); } template <typename T> inline Mod<2> Power( const Mod<2>& n , const T& exponent ) { return exponent == 0 ? Mod<2>::one() : n; } template <> inline Mod<2> Square<Mod<2> >( const Mod<2>& t ) { return t; } template <INT_TYPE_FOR_MOD M> inline void swap( Mod<M>& n0 , Mod<M>& n1 ) noexcept { n0.swap( n1 ); } template <INT_TYPE_FOR_MOD M> inline string to_string( const Mod<M>& n ) noexcept { return to_string( n.Represent() ) + " + MZ"; } template<INT_TYPE_FOR_MOD M , class Traits> inline basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os , const Mod<M>& n ) { return os << n.Represent(); } // 以下は // https://yukicoder.me/submissions/803764 // のmain関数に上のライブラリを適用したもの。 int main() { constexpr const ll bound_N = 1000000000000000000; CIN( ll , N ); assert( 1 <= N && N <= bound_N ); constexpr const int bound_M = 100000; CIN( int , M ); assert( 1 <= M && M <= bound_M ); if( N < M ){ RETURN( 0 ); } constexpr const ll P = 998244353; Mod<P> answer{ 2 }; ll N_copy = N % ( P - 1 ); answer.PositivePower( N_copy ); Mod<P> combination{ N }; answer--; if( M != 1 ){ answer -= N; } FOR( i , 2 , M ){ combination *= N + 1 - i; combination *= Mod<P>::Inverse( i ); answer -= combination; } RETURN( answer ); }