結果

問題 No.2130 分配方法の数え上げ mod 998244353
ユーザー 👑 p-adicp-adic
提出日時 2023-01-01 18:40:51
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
WA  
実行時間 -
コード長 16,532 bytes
コンパイル時間 2,346 ms
コンパイル使用メモリ 203,516 KB
実行使用メモリ 6,944 KB
最終ジャッジ日時 2024-05-05 05:54:06
合計ジャッジ時間 3,113 ms
ジャッジサーバーID
(参考情報)
judge2 / judge4
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
6,816 KB
testcase_01 AC 2 ms
6,940 KB
testcase_02 AC 2 ms
6,944 KB
testcase_03 AC 2 ms
6,940 KB
testcase_04 AC 1 ms
6,940 KB
testcase_05 AC 1 ms
6,940 KB
testcase_06 AC 1 ms
6,944 KB
testcase_07 AC 2 ms
6,940 KB
testcase_08 AC 1 ms
6,940 KB
testcase_09 AC 2 ms
6,940 KB
testcase_10 AC 2 ms
6,940 KB
testcase_11 AC 2 ms
6,944 KB
testcase_12 AC 1 ms
6,944 KB
testcase_13 AC 2 ms
6,940 KB
testcase_14 AC 2 ms
6,940 KB
testcase_15 AC 1 ms
6,940 KB
testcase_16 AC 2 ms
6,940 KB
testcase_17 AC 1 ms
6,940 KB
testcase_18 AC 2 ms
6,944 KB
testcase_19 AC 2 ms
6,940 KB
testcase_20 AC 2 ms
6,940 KB
testcase_21 WA -
testcase_22 WA -
testcase_23 WA -
testcase_24 WA -
testcase_25 WA -
testcase_26 WA -
testcase_27 WA -
testcase_28 AC 1 ms
6,940 KB
testcase_29 WA -
testcase_30 AC 2 ms
6,944 KB
testcase_31 AC 2 ms
6,944 KB
testcase_32 AC 2 ms
6,940 KB
testcase_33 AC 2 ms
6,940 KB
testcase_34 AC 2 ms
6,940 KB
testcase_35 WA -
testcase_36 AC 1 ms
6,940 KB
testcase_37 WA -
権限があれば一括ダウンロードができます

ソースコード

diff #

// 手持ちの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( INT_TYPE_FOR_MOD( 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 );  
}
0