#line 1 "verify/fps/LC_kth_term_of_linearly_recurrent_sequence.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/kth_term_of_linearly_recurrent_sequence"
#line 2 "template/template.hpp"
#include <bits/stdc++.h>
using namespace std ;
#line 2 "template/macro.hpp"
#define rep(i, a, b) for (int i = (a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b) - 1; i >= (a); i--)
#define ALL(v) (v).begin(), (v).end()
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v, x) int(lower_bound(ALL(v), (x)) - (v).begin())
#define UB(v, x) int(upper_bound(ALL(v), (x)) - (v).begin())
#define YN(b) cout << ((b) ? "YES" : "NO") << "\n";
#define Yn(b) cout << ((b) ? "Yes" : "No") << "\n";
#define yn(b) cout << ((b) ? "yes" : "no") << "\n";
#line 6 "template/template.hpp"
#line 2 "template/util.hpp"
using uint = unsigned int ;
using ll = long long int ;
using ull = unsigned long long ;
using i128 = __int128_t ;
using u128 = __uint128_t ;
template < class T , class S = T >
S SUM ( const vector < T > & a ) {
return accumulate ( ALL ( a ), S ( 0 ));
}
template < class T >
inline bool chmin ( T & a , T b ) {
if ( a > b ) {
a = b ;
return true ;
}
return false ;
}
template < class T >
inline bool chmax ( T & a , T b ) {
if ( a < b ) {
a = b ;
return true ;
}
return false ;
}
template < class T >
int popcnt ( T x ) {
return __builtin_popcountll ( x );
}
template < class T >
int topbit ( T x ) {
return ( x == 0 ? - 1 : 63 - __builtin_clzll ( x ));
}
template < class T >
int lowbit ( T x ) {
return ( x == 0 ? - 1 : __builtin_ctzll ( x ));
}
#line 8 "template/template.hpp"
#line 2 "template/inout.hpp"
struct Fast {
Fast () {
cin . tie ( nullptr );
ios_base :: sync_with_stdio ( false );
cout << fixed << setprecision ( 15 );
}
} fast ;
template < class T1 , class T2 >
istream & operator >> ( istream & is , pair < T1 , T2 > & p ) {
return is >> p . first >> p . second ;
}
template < class T1 , class T2 >
ostream & operator << ( ostream & os , const pair < T1 , T2 > & p ) {
return os << p . first << " " << p . second ;
}
template < class T >
istream & operator >> ( istream & is , vector < T > & a ) {
for ( auto & v : a ) is >> v ;
return is ;
}
template < class T >
ostream & operator << ( ostream & os , const vector < T > & a ) {
for ( auto it = a . begin (); it != a . end ();) {
os << * it ;
if ( ++ it != a . end ()) os << " " ;
}
return os ;
}
template < class T >
ostream & operator << ( ostream & os , const set < T > & st ) {
os << "{" ;
for ( auto it = st . begin (); it != st . end ();) {
os << * it ;
if ( ++ it != st . end ()) os << "," ;
}
os << "}" ;
return os ;
}
template < class T1 , class T2 >
ostream & operator << ( ostream & os , const map < T1 , T2 > & mp ) {
os << "{" ;
for ( auto it = mp . begin (); it != mp . end ();) {
os << it -> first << ":" << it -> second ;
if ( ++ it != mp . end ()) os << "," ;
}
os << "}" ;
return os ;
}
void in () {}
template < typename T , class ... U >
void in ( T & t , U & ... u ) {
cin >> t ;
in ( u ...);
}
void out () { cout << " \n " ; }
template < typename T , class ... U , char sep = ' ' >
void out ( const T & t , const U & ... u ) {
cout << t ;
if ( sizeof ...( u )) cout << sep ;
out ( u ...);
}
#line 10 "template/template.hpp"
#line 2 "template/debug.hpp"
#ifdef LOCAL
#define debug 1
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define debug 0
#define show(...) true
#endif
template < class T >
void _show ( int i , T name ) {
cerr << '\n' ;
}
template < class T1 , class T2 , class ... T3 >
void _show ( int i , const T1 & a , const T2 & b , const T3 & ... c ) {
for (; a [ i ] != ',' && a [ i ] != '\0' ; i ++ ) cerr << a [ i ];
cerr << ":" << b << " " ;
_show ( i + 1 , a , c ...);
}
#line 2 "modint/modint.hpp"
template < unsigned int m = 998244353 >
struct ModInt {
using mint = ModInt ;
unsigned int _v ;
static constexpr unsigned int get_mod () { return m ; }
static mint raw ( int v ) {
mint x ;
x . _v = v ;
return x ;
}
ModInt () : _v ( 0 ) {}
ModInt ( int64_t v ) {
long long x = ( long long )( v % ( long long )( umod ()));
if ( x < 0 ) x += umod ();
_v = ( unsigned int )( x );
}
unsigned int val () const { return _v ; }
mint & operator ++ () {
_v ++ ;
if ( _v == umod ()) _v = 0 ;
return * this ;
}
mint & operator -- () {
if ( _v == 0 ) _v = umod ();
_v -- ;
return * this ;
}
mint operator ++ ( int ) {
mint result = * this ;
++* this ;
return result ;
}
mint operator -- ( int ) {
mint result = * this ;
--* this ;
return result ;
}
mint & operator += ( const mint & rhs ) {
_v += rhs . _v ;
if ( _v >= umod ()) _v -= umod ();
return * this ;
}
mint & operator -= ( const mint & rhs ) {
_v -= rhs . _v ;
if ( _v >= umod ()) _v += umod ();
return * this ;
}
mint & operator *= ( const mint & rhs ) {
unsigned long long z = _v ;
z *= rhs . _v ;
_v = ( unsigned int )( z % umod ());
return * this ;
}
mint & operator /= ( const mint & rhs ) { return * this = * this * rhs . inv (); }
mint operator + () const { return * this ; }
mint operator - () const { return mint () - * this ; }
mint pow ( long long n ) const {
assert ( 0 <= n );
mint x = * this , r = 1 ;
while ( n ) {
if ( n & 1 ) r *= x ;
x *= x ;
n >>= 1 ;
}
return r ;
}
mint inv () const {
assert ( _v );
return pow ( umod () - 2 );
}
friend mint operator + ( const mint & lhs , const mint & rhs ) {
return mint ( lhs ) += rhs ;
}
friend mint operator - ( const mint & lhs , const mint & rhs ) {
return mint ( lhs ) -= rhs ;
}
friend mint operator * ( const mint & lhs , const mint & rhs ) {
return mint ( lhs ) *= rhs ;
}
friend mint operator / ( const mint & lhs , const mint & rhs ) {
return mint ( lhs ) /= rhs ;
}
friend bool operator == ( const mint & lhs , const mint & rhs ) {
return lhs . _v == rhs . _v ;
}
friend bool operator != ( const mint & lhs , const mint & rhs ) {
return lhs . _v != rhs . _v ;
}
friend istream & operator >> ( istream & is , mint & x ) {
return is >> x . _v ;
}
friend ostream & operator << ( ostream & os , const mint & x ) {
return os << x . val ();
}
private:
static constexpr unsigned int umod () { return m ; }
};
#line 5 "verify/fps/LC_kth_term_of_linearly_recurrent_sequence.test.cpp"
using mint = ModInt < 998244353 > ;
#line 2 "fps/fps-ntt-friendly.hpp"
#line 2 "fft/ntt.hpp"
template < class mint >
struct NTT {
static constexpr unsigned int mod = mint :: get_mod ();
static constexpr unsigned long long pow_constexpr ( unsigned long long x , unsigned long long n , unsigned long long m ) {
unsigned long long y = 1 ;
while ( n ) {
if ( n & 1 ) y = y * x % m ;
x = x * x % m ;
n >>= 1 ;
}
return y ;
}
static constexpr unsigned int get_g () {
unsigned long long x = 2 ;
while ( pow_constexpr ( x , ( mod - 1 ) >> 1 , mod ) == 1 ) x += 1 ;
return x ;
}
static constexpr unsigned int g = get_g ();
static constexpr int rank2 = __builtin_ctzll ( mod - 1 );
array < mint , rank2 + 1 > root ;
array < mint , rank2 + 1 > iroot ;
array < mint , max ( 0 , rank2 - 2 + 1 ) > rate2 ;
array < mint , max ( 0 , rank2 - 2 + 1 ) > irate2 ;
array < mint , max ( 0 , rank2 - 3 + 1 ) > rate3 ;
array < mint , max ( 0 , rank2 - 3 + 1 ) > irate3 ;
NTT () {
root [ rank2 ] = mint ( g ). pow (( mod - 1 ) >> rank2 );
iroot [ rank2 ] = root [ rank2 ]. inv ();
for ( int i = rank2 - 1 ; i >= 0 ; i -- ) {
root [ i ] = root [ i + 1 ] * root [ i + 1 ];
iroot [ i ] = iroot [ i + 1 ] * iroot [ i + 1 ];
}
{
mint prod = 1 , iprod = 1 ;
for ( int i = 0 ; i <= rank2 - 2 ; i ++ ) {
rate2 [ i ] = root [ i + 2 ] * prod ;
irate2 [ i ] = iroot [ i + 2 ] * iprod ;
prod *= iroot [ i + 2 ];
iprod *= root [ i + 2 ];
}
}
{
mint prod = 1 , iprod = 1 ;
for ( int i = 0 ; i <= rank2 - 3 ; i ++ ) {
rate3 [ i ] = root [ i + 3 ] * prod ;
irate3 [ i ] = iroot [ i + 3 ] * iprod ;
prod *= iroot [ i + 3 ];
iprod *= root [ i + 3 ];
}
}
}
void ntt ( vector < mint >& a ) {
int n = int ( a . size ());
int h = __builtin_ctzll (( unsigned int ) n );
a . resize ( 1 << h );
int len = 0 ; // a[i, i+(n>>len), i+2*(n>>len), ..] is transformed
while ( len < h ) {
if ( h - len == 1 ) {
int p = 1 << ( h - len - 1 );
mint rot = 1 ;
for ( int s = 0 ; s < ( 1 << len ); s ++ ) {
int offset = s << ( h - len );
for ( int i = 0 ; i < p ; i ++ ) {
auto l = a [ i + offset ];
auto r = a [ i + offset + p ] * rot ;
a [ i + offset ] = l + r ;
a [ i + offset + p ] = l - r ;
}
if ( s + 1 != ( 1 << len )) rot *= rate2 [ __builtin_ctzll ( ~ ( unsigned int )( s ))];
}
len ++ ;
} else {
// 4-base
int p = 1 << ( h - len - 2 );
mint rot = 1 , imag = root [ 2 ];
for ( int s = 0 ; s < ( 1 << len ); s ++ ) {
mint rot2 = rot * rot ;
mint rot3 = rot2 * rot ;
int offset = s << ( h - len );
for ( int i = 0 ; i < p ; i ++ ) {
auto mod2 = 1ULL * mint :: get_mod () * mint :: get_mod ();
auto a0 = 1ULL * a [ i + offset ]. val ();
auto a1 = 1ULL * a [ i + offset + p ]. val () * rot . val ();
auto a2 = 1ULL * a [ i + offset + 2 * p ]. val () * rot2 . val ();
auto a3 = 1ULL * a [ i + offset + 3 * p ]. val () * rot3 . val ();
auto a1na3imag = 1ULL * mint ( a1 + mod2 - a3 ). val () * imag . val ();
auto na2 = mod2 - a2 ;
a [ i + offset ] = a0 + a2 + a1 + a3 ;
a [ i + offset + 1 * p ] = a0 + a2 + ( 2 * mod2 - ( a1 + a3 ));
a [ i + offset + 2 * p ] = a0 + na2 + a1na3imag ;
a [ i + offset + 3 * p ] = a0 + na2 + ( mod2 - a1na3imag );
}
if ( s + 1 != ( 1 << len )) rot *= rate3 [ __builtin_ctzll ( ~ ( unsigned int )( s ))];
}
len += 2 ;
}
}
}
void intt ( vector < mint >& a ) {
int n = int ( a . size ());
int h = __builtin_ctzll (( unsigned int ) n );
a . resize ( 1 << h );
int len = h ; // a[i, i+(n>>len), i+2*(n>>len), ..] is transformed
while ( len ) {
if ( len == 1 ) {
int p = 1 << ( h - len );
mint irot = 1 ;
for ( int s = 0 ; s < ( 1 << ( len - 1 )); s ++ ) {
int offset = s << ( h - len + 1 );
for ( int i = 0 ; i < p ; i ++ ) {
auto l = a [ i + offset ];
auto r = a [ i + offset + p ];
a [ i + offset ] = l + r ;
a [ i + offset + p ] = ( unsigned long long )( mint :: get_mod () + l . val () - r . val ()) * irot . val ();
}
if ( s + 1 != ( 1 << ( len - 1 ))) irot *= irate2 [ __builtin_ctzll ( ~ ( unsigned int )( s ))];
}
len -- ;
} else {
// 4-base
int p = 1 << ( h - len );
mint irot = 1 , iimag = iroot [ 2 ];
for ( int s = 0 ; s < ( 1 << ( len - 2 )); s ++ ) {
mint irot2 = irot * irot ;
mint irot3 = irot2 * irot ;
int offset = s << ( h - len + 2 );
for ( int i = 0 ; i < p ; i ++ ) {
auto a0 = 1ULL * a [ i + offset + 0 * p ]. val ();
auto a1 = 1ULL * a [ i + offset + 1 * p ]. val ();
auto a2 = 1ULL * a [ i + offset + 2 * p ]. val ();
auto a3 = 1ULL * a [ i + offset + 3 * p ]. val ();
auto a2na3iimag = 1ULL * mint (( mint :: get_mod () + a2 - a3 ) * iimag . val ()). val ();
a [ i + offset ] = a0 + a1 + a2 + a3 ;
a [ i + offset + 1 * p ] = ( a0 + ( mint :: get_mod () - a1 ) + a2na3iimag ) * irot . val ();
a [ i + offset + 2 * p ] = ( a0 + a1 + ( mint :: get_mod () - a2 ) + ( mint :: get_mod () - a3 )) * irot2 . val ();
a [ i + offset + 3 * p ] = ( a0 + ( mint :: get_mod () - a1 ) + ( mint :: get_mod () - a2na3iimag )) * irot3 . val ();
}
if ( s + 1 != ( 1 << ( len - 2 ))) irot *= irate3 [ __builtin_ctzll ( ~ ( unsigned int )( s ))];
}
len -= 2 ;
}
}
mint e = mint ( n ). inv ();
for ( auto & x : a ) x *= e ;
}
vector < mint > multiply ( const vector < mint >& a , const vector < mint >& b ) {
if ( a . empty () || b . empty ()) return vector < mint > ();
int n = a . size (), m = b . size ();
int sz = n + m - 1 ;
if ( n <= 30 || m <= 30 ) {
if ( n > 30 ) return multiply ( b , a );
vector < mint > res ( sz );
for ( int i = 0 ; i < n ; i ++ )
for ( int j = 0 ; j < m ; j ++ ) res [ i + j ] += a [ i ] * b [ j ];
return res ;
}
int sz1 = 1 ;
while ( sz1 < sz ) sz1 <<= 1 ;
vector < mint > res ( sz1 );
for ( int i = 0 ; i < n ; i ++ ) res [ i ] = a [ i ];
ntt ( res );
if ( a == b )
for ( int i = 0 ; i < sz1 ; i ++ ) res [ i ] *= res [ i ];
else {
vector < mint > c ( sz1 );
for ( int i = 0 ; i < m ; i ++ ) c [ i ] = b [ i ];
ntt ( c );
for ( int i = 0 ; i < sz1 ; i ++ ) res [ i ] *= c [ i ];
}
intt ( res );
res . resize ( sz );
return res ;
}
// c[i]=sum[j]a[j]b[i+j]
vector < mint > middle_product ( const vector < mint >& a , const vector < mint >& b ) {
if ( b . empty () || a . size () > b . size ()) return {};
int n = a . size (), m = b . size ();
int sz = m - n + 1 ;
if ( n <= 30 || sz <= 30 ) {
vector < mint > res ( sz );
for ( int i = 0 ; i < sz ; i ++ )
for ( int j = 0 ; j < n ; j ++ ) res [ i ] += a [ j ] * b [ i + j ];
return res ;
}
int sz1 = 1 ;
while ( sz1 < m ) sz1 <<= 1 ;
vector < mint > res ( sz1 ), b2 ( sz1 );
reverse_copy ( a . begin (), a . end (), res . begin ());
copy ( b . begin (), b . end (), b2 . begin ());
ntt ( res );
ntt ( b2 );
for ( int i = 0 ; i < res . size (); i ++ ) res [ i ] *= b2 [ i ];
intt ( res );
res . resize ( m );
res . erase ( res . begin (), res . begin () + n - 1 );
return res ;
}
void ntt_doubling ( vector < mint >& a ) {
int n = ( int ) a . size ();
auto b = a ;
intt ( b );
mint r = 1 , zeta = mint ( g ). pow (( mint :: get_mod () - 1 ) / ( n << 1 ));
for ( int i = 0 ; i < n ; i ++ ) b [ i ] *= r , r *= zeta ;
ntt ( b );
copy ( b . begin (), b . end (), back_inserter ( a ));
}
};
/**
* @brief NTT (数論変換)
* @docs docs/fft/ntt.md
*/
#line 2 "fps/formal-power-series.hpp"
template < class mint >
struct FormalPowerSeries : vector < mint > {
using vector < mint >:: vector ;
using FPS = FormalPowerSeries ;
FPS & operator += ( const FPS & r ) {
if ( r . size () > this -> size ()) this -> resize ( r . size ());
for ( int i = 0 ; i < ( int ) r . size (); i ++ ) ( * this )[ i ] += r [ i ];
return * this ;
}
FPS & operator += ( const mint & r ) {
if ( this -> empty ()) this -> resize ( 1 );
( * this )[ 0 ] += r ;
return * this ;
}
FPS & operator -= ( const FPS & r ) {
if ( r . size () > this -> size ()) this -> resize ( r . size ());
for ( int i = 0 ; i < ( int ) r . size (); i ++ ) ( * this )[ i ] -= r [ i ];
return * this ;
}
FPS & operator -= ( const mint & r ) {
if ( this -> empty ()) this -> resize ( 1 );
( * this )[ 0 ] -= r ;
return * this ;
}
FPS & operator *= ( const mint & v ) {
for ( int k = 0 ; k < ( int ) this -> size (); k ++ ) ( * this )[ k ] *= v ;
return * this ;
}
FPS & operator /= ( const FPS & r ) {
if ( this -> size () < r . size ()) {
this -> clear ();
return * this ;
}
int n = this -> size () - r . size () + 1 ;
if (( int ) r . size () <= 64 ) {
FPS f ( * this ), g ( r );
g . shrink ();
mint coeff = g . at ( g . size () - 1 ). inv ();
for ( auto & x : g ) x *= coeff ;
int deg = ( int ) f . size () - ( int ) g . size () + 1 ;
int gs = g . size ();
FPS quo ( deg );
for ( int i = deg - 1 ; i >= 0 ; i -- ) {
quo [ i ] = f [ i + gs - 1 ];
for ( int j = 0 ; j < gs ; j ++ ) f [ i + j ] -= quo [ i ] * g [ j ];
}
* this = quo * coeff ;
this -> resize ( n , mint ( 0 ));
return * this ;
}
return * this = (( * this ). rev (). pre ( n ) * r . rev (). inv ( n )). pre ( n ). rev ();
}
FPS & operator %= ( const FPS & r ) {
* this -= * this / r * r ;
shrink ();
return * this ;
}
FPS operator + ( const FPS & r ) const { return FPS ( * this ) += r ; }
FPS operator + ( const mint & v ) const { return FPS ( * this ) += v ; }
FPS operator - ( const FPS & r ) const { return FPS ( * this ) -= r ; }
FPS operator - ( const mint & v ) const { return FPS ( * this ) -= v ; }
FPS operator * ( const FPS & r ) const { return FPS ( * this ) *= r ; }
FPS operator * ( const mint & v ) const { return FPS ( * this ) *= v ; }
FPS operator / ( const FPS & r ) const { return FPS ( * this ) /= r ; }
FPS operator % ( const FPS & r ) const { return FPS ( * this ) %= r ; }
FPS operator - () const {
FPS ret ( this -> size ());
for ( int i = 0 ; i < ( int ) this -> size (); i ++ ) ret [ i ] = - ( * this )[ i ];
return ret ;
}
void shrink () {
while ( this -> size () && this -> back () == mint ( 0 )) this -> pop_back ();
}
FPS rev () const {
FPS ret ( * this );
reverse ( begin ( ret ), end ( ret ));
return ret ;
}
FPS dot ( FPS r ) const {
FPS ret ( min ( this -> size (), r . size ()));
for ( int i = 0 ; i < ( int ) ret . size (); i ++ ) ret [ i ] = ( * this )[ i ] * r [ i ];
return ret ;
}
FPS pre ( int sz ) const {
return FPS ( begin ( * this ), begin ( * this ) + min (( int ) this -> size (), sz ));
}
FPS operator >>= ( int sz ) {
assert ( sz >= 0 );
if (( int ) this -> size () <= sz ) return {};
this -> erase ( this -> begin (), this -> begin () + sz );
return * this ;
}
FPS operator >> ( int sz ) const {
if (( int ) this -> size () <= sz ) return {};
FPS ret ( * this );
ret . erase ( ret . begin (), ret . begin () + sz );
return ret ;
}
FPS operator <<= ( int sz ) {
assert ( sz >= 0 );
this -> insert ( this -> begin (), sz , mint ( 0 ));
return * this ;
}
FPS operator << ( int sz ) const {
FPS ret ( * this );
ret . insert ( ret . begin (), sz , mint ( 0 ));
return ret ;
}
FPS diff () const {
const int n = ( int ) this -> size ();
FPS ret ( max ( 0 , n - 1 ));
mint one ( 1 ), coeff ( 1 );
for ( int i = 1 ; i < n ; i ++ ) {
ret [ i - 1 ] = ( * this )[ i ] * coeff ;
coeff += one ;
}
return ret ;
}
FPS integral () const {
const int n = ( int ) this -> size ();
FPS ret ( n + 1 );
ret [ 0 ] = mint ( 0 );
if ( n > 0 ) ret [ 1 ] = mint ( 1 );
auto mod = mint :: get_mod ();
for ( int i = 2 ; i <= n ; i ++ ) ret [ i ] = ( - ret [ mod % i ]) * ( mod / i );
for ( int i = 0 ; i < n ; i ++ ) ret [ i + 1 ] *= ( * this )[ i ];
return ret ;
}
mint eval ( mint x ) const {
mint r = 0 , w = 1 ;
for ( auto & v : * this ) r += w * v , w *= x ;
return r ;
}
FPS log ( int deg = - 1 ) const {
assert (( * this )[ 0 ] == mint ( 1 ));
if ( deg == - 1 ) deg = ( int ) this -> size ();
return ( this -> diff () * this -> inv ( deg )). pre ( deg - 1 ). integral ();
}
FPS pow ( int64_t k , int deg = - 1 ) const {
const int n = ( int ) this -> size ();
if ( deg == - 1 ) deg = n ;
if ( k == 0 ) {
FPS ret ( deg );
if ( deg ) ret [ 0 ] = 1 ;
return ret ;
}
for ( int i = 0 ; i < n ; i ++ ) {
if (( * this )[ i ] != mint ( 0 )) {
mint rev = mint ( 1 ) / ( * this )[ i ];
FPS ret = ((( * this * rev ) >> i ). log ( deg ) * k ). exp ( deg );
ret *= ( * this )[ i ]. pow ( k );
ret = ( ret << ( i * k )). pre ( deg );
if (( int ) ret . size () < deg ) ret . resize ( deg , mint ( 0 ));
return ret ;
}
if ( __int128_t ( i + 1 ) * k >= deg ) return FPS ( deg , mint ( 0 ));
}
return FPS ( deg , mint ( 0 ));
}
static void * ntt_ptr ;
static void set_ntt ();
FPS & operator *= ( const FPS & r );
FPS middle_product ( const FPS & r ) const ;
void ntt ();
void intt ();
void ntt_doubling ();
static int ntt_root ();
FPS inv ( int deg = - 1 ) const ;
FPS exp ( int deg = - 1 ) const ;
};
template < typename mint >
void * FormalPowerSeries < mint >:: ntt_ptr = nullptr ;
#line 5 "fps/fps-ntt-friendly.hpp"
template < class mint >
void FormalPowerSeries < mint >:: set_ntt () {
if ( ! ntt_ptr ) ntt_ptr = new NTT < mint > ;
}
template < class mint >
FormalPowerSeries < mint >& FormalPowerSeries < mint >:: operator *= ( const FormalPowerSeries < mint >& r ) {
if ( this -> empty () || r . empty ()) {
this -> clear ();
return * this ;
}
set_ntt ();
auto ret = static_cast < NTT < mint >*> ( ntt_ptr ) -> multiply ( * this , r );
return * this = FormalPowerSeries < mint > ( ret . begin (), ret . end ());
}
template < class mint >
FormalPowerSeries < mint > FormalPowerSeries < mint >:: middle_product ( const FormalPowerSeries < mint >& r ) const {
set_ntt ();
auto ret = static_cast < NTT < mint >*> ( ntt_ptr ) -> middle_product ( * this , r );
return FormalPowerSeries < mint > ( ret . begin (), ret . end ());
}
template < class mint >
void FormalPowerSeries < mint >:: ntt () {
set_ntt ();
static_cast < NTT < mint >*> ( ntt_ptr ) -> ntt ( * this );
}
template < class mint >
void FormalPowerSeries < mint >:: intt () {
set_ntt ();
static_cast < NTT < mint >*> ( ntt_ptr ) -> intt ( * this );
}
template < class mint >
void FormalPowerSeries < mint >:: ntt_doubling () {
set_ntt ();
static_cast < NTT < mint >*> ( ntt_ptr ) -> ntt_doubling ( * this );
}
template < typename mint >
int FormalPowerSeries < mint >:: ntt_root () {
set_ntt ();
return static_cast < NTT < mint >*> ( ntt_ptr ) -> g ;
}
template < typename mint >
FormalPowerSeries < mint > FormalPowerSeries < mint >:: inv ( int deg ) const {
assert (( * this )[ 0 ] != mint ( 0 ));
if ( deg == - 1 ) deg = ( * this ). size ();
FPS ret { mint ( 1 ) / ( * this )[ 0 ]};
for ( int i = 1 ; i < deg ; i <<= 1 )
ret = ( ret + ret - ret * ret * ( * this ). pre ( i << 1 )). pre ( i << 1 );
return ret . pre ( deg );
}
template < typename mint >
FormalPowerSeries < mint > FormalPowerSeries < mint >:: exp ( int deg ) const {
assert (( * this )[ 0 ] == mint ( 0 ));
if ( deg == - 1 ) deg = ( * this ). size ();
FPS ret { mint ( 1 )};
for ( int i = 1 ; i < deg ; i <<= 1 )
ret = ( ret * (( * this ). pre ( i << 1 ) - ret . log ( i << 1 ) + 1 )). pre ( i << 1 );
return ret . pre ( deg );
}
#line 7 "verify/fps/LC_kth_term_of_linearly_recurrent_sequence.test.cpp"
using fps = FormalPowerSeries < mint > ;
#line 1 "fps/linearly-recurrent-sequence.hpp"
#pragma
#line 3 "fps/berlekamp-massey.hpp"
template < class mint >
FormalPowerSeries < mint > BerlekampMassey ( const FormalPowerSeries < mint >& a ) {
int n = a . size ();
FormalPowerSeries < mint > b , c ;
b . reserve ( n + 1 ), c . reserve ( n + 1 );
b . push_back ( 1 ), c . push_back ( 1 );
mint y = 1 ;
for ( int k = 0 ; k < n ; k ++ ) {
mint x = 0 ;
for ( int i = 0 ; i < c . size (); i ++ ) x += c [ i ] * a [ k - i ];
b . insert ( b . begin (), 0 );
if ( x == 0 ) continue ;
mint v = x / y ;
if ( b . size () > c . size ()) {
for ( int i = 0 ; i < b . size (); i ++ ) b [ i ] *= - v ;
for ( int i = 0 ; i < c . size (); i ++ ) b [ i ] += c [ i ];
swap ( b , c );
y = x ;
} else {
for ( int i = 0 ; i < b . size (); i ++ ) c [ i ] -= v * b [ i ];
}
}
return c ;
}
/**
* @brief Berlekamp-Massey
* @docs docs/fps/berlekamp-massey.md
*/
#line 3 "fps/bostan-mori.hpp"
// [x^n]f(x)/g(x)
template < class mint >
mint BostanMori ( FormalPowerSeries < mint > f , FormalPowerSeries < mint > g , long long n ) {
g . shrink ();
mint ret = 0 ;
if ( f . size () >= g . size ()) {
auto q = f / g ;
if ( n < q . size ()) ret += q [ n ];
f -= q * g ;
f . shrink ();
}
if ( f . empty ()) return ret ;
FormalPowerSeries < mint >:: set_ntt ();
if ( ! FormalPowerSeries < mint >:: ntt_ptr ) {
f . resize ( g . size () - 1 );
for (; n > 0 ; n >>= 1 ) {
auto g1 = g ;
for ( int i = 1 ; i < g1 . size (); i += 2 ) g1 [ i ] = - g1 [ i ];
auto p = f * g1 , q = g * g1 ;
if ( n & 1 ) {
for ( int i = 0 ; i < f . size (); i ++ ) f [ i ] = p [( i << 1 ) | 1 ];
} else {
for ( int i = 0 ; i < f . size (); i ++ ) f [ i ] = p [ i << 1 ];
}
for ( int i = 0 ; i < g . size (); i ++ ) g [ i ] = q [ i << 1 ];
}
return ret + f [ 0 ] / g [ 0 ];
} else {
int m = 1 , log = 0 ;
while ( m < g . size ()) m <<= 1 , log ++ ;
mint wi = mint ( FormalPowerSeries < mint >:: ntt_root ()). inv (). pow (( mint :: get_mod () - 1 ) >> ( log + 1 ));
vector < int > rev ( m );
for ( int i = 0 ; i < rev . size (); i ++ ) rev [ i ] = ( rev [ i / 2 ] / 2 ) | (( i & 1 ) << ( log - 1 ));
vector < mint > pow ( m , 1 );
for ( int i = 1 ; i < m ; i ++ ) pow [ rev [ i ]] = pow [ rev [ i - 1 ]] * wi ;
f . resize ( m ), g . resize ( m );
f . ntt (), g . ntt ();
mint inv2 = mint ( 2 ). inv ();
for (; n >= m ; n >>= 1 ) {
f . ntt_doubling (), g . ntt_doubling ();
if ( n & 1 ) {
for ( int i = 0 ; i < m ; i ++ ) f [ i ] = ( f [ i << 1 ] * g [( i << 1 ) | 1 ] - f [( i << 1 ) | 1 ] * g [ i << 1 ]) * inv2 * pow [ i ];
} else {
for ( int i = 0 ; i < m ; i ++ ) f [ i ] = ( f [ i << 1 ] * g [( i << 1 ) | 1 ] + f [( i << 1 ) | 1 ] * g [ i << 1 ]) * inv2 ;
}
for ( int i = 0 ; i < m ; i ++ ) g [ i ] = g [ i << 1 ] * g [( i << 1 ) | 1 ];
f . resize ( m ), g . resize ( m );
}
f . intt (), g . intt ();
return ret + ( f * g . inv ())[ n ];
}
}
/**
* @brief Bostan-Mori
* @docs docs/fps/bostan-mori.md
*/
#line 3 "fps/inverse-shift.hpp"
// [x^n,...,x^{n+k-1}]1/f(x)
template < class mint >
FormalPowerSeries < mint > InverseShift ( FormalPowerSeries < mint > f , long long n , int k = - 1 ) {
using fps = FormalPowerSeries < mint > ;
assert ( f [ 0 ] != 0 );
if ( k == - 1 ) k = f . size ();
int m = 1 ;
while ( m < k ) m <<= 1 ;
int log = __builtin_ctz (( unsigned int ) m );
mint w = mint ( fps :: ntt_root ()). pow (( mint :: get_mod () - 1 ) >> ( log + 1 ));
mint wi = w . inv ();
vector < int > rev ( m );
for ( int i = 0 ; i < rev . size (); i ++ ) rev [ i ] = ( rev [ i / 2 ] / 2 ) | (( i & 1 ) << ( log - 1 ));
mint inv2 = mint ( 2 ). inv ();
f . resize ( m );
f . ntt ();
auto rec = [ & ]( auto & rec , long long n ) -> void {
if ( n < m ) {
f . intt ();
f = f . inv ( n + m );
f >>= n ;
f . ntt ();
return ;
}
f . ntt_doubling ();
assert ( f . size () == 2 * m );
auto f1 = f ;
for ( int i = 0 ; i < m ; i ++ ) swap ( f1 [ i << 1 ], f1 [( i << 1 ) | 1 ]);
for ( int i = 0 ; i < m ; i ++ ) f [ i ] = f [ i << 1 ] * f [( i << 1 ) | 1 ];
f . resize ( m );
rec ( rec , ( n - m + 1 ) / 2 );
if ((( n - m ) & 1 ) == 0 ) {
f . resize ( 2 * m );
for ( int i = m - 1 ; i >= 0 ; i -- ) {
f [( i << 1 ) | 1 ] = f [ i ];
f [ i << 1 ] = f [ i ];
}
} else {
mint p = 1 ;
for ( auto i : rev ) f [ i ] *= p , p *= w ;
f . resize ( 2 * m );
for ( int i = m - 1 ; i >= 0 ; i -- ) {
f [( i << 1 ) | 1 ] = - f [ i ];
f [ i << 1 ] = f [ i ];
}
}
for ( int i = 0 ; i < 2 * m ; i ++ ) f [ i ] *= f1 [ i ];
auto odd = fps ( f . begin () + m , f . end ());
odd . intt ();
mint p = 1 ;
for ( int i = 0 ; i < m ; i ++ ) odd [ i ] *= p , p *= wi ;
odd . ntt ();
f . resize ( m );
for ( int i = 0 ; i < m ; i ++ ) f [ i ] = ( f [ i ] - odd [ i ]) * inv2 ;
};
rec ( rec , n );
f . intt ();
f . resize ( k );
return f ;
}
/**
* @brief Inverse の次数シフト
* @docs docs/fps/inverse-shift.md
*/
#line 6 "fps/linearly-recurrent-sequence.hpp"
// a[i]=sum[j=1~d]c[j]a[i-j], i>=d
// find a[n]
template < class mint >
mint LinearyRecurrentSequence ( FormalPowerSeries < mint > a , FormalPowerSeries < mint > c , long long n ) {
assert ( a . size () == c . size ());
if ( n < a . size ()) return a [ n ];
while ( ! c . empty () && c . back () == 0 ) c . pop_back ();
if ( c . size () < a . size ()) {
int z = a . size () - c . size ();
n -= z ;
a . erase ( a . begin (), a . begin () + z );
}
int d = c . size ();
FormalPowerSeries < mint > q ( d + 1 );
q [ 0 ] = 1 ;
for ( int i = 0 ; i < d ; i ++ ) q [ i + 1 ] = - c [ i ];
auto p = ( a * q ). pre ( d );
return BostanMori ( p , q , n );
}
// a[i]=sum[j=1~d]c[j]a[i-j], i>=d
// find a[n],a[n+1],...,a[n+k-1]
template < class mint >
FormalPowerSeries < mint > LinearyRecurrentSequence ( FormalPowerSeries < mint > a , FormalPowerSeries < mint > c , long long n , int k ) {
assert ( a . size () == c . size ());
if ( n + k < a . size ()) {
a >>= ( int ) n ;
return a . pre ( k );
}
while ( ! c . empty () && c . back () == 0 ) c . pop_back ();
int d = c . size ();
FormalPowerSeries < mint > ret {};
if ( c . size () < a . size ()) {
int z = a . size () - c . size ();
if ( n < z ) {
ret . reserve ( k );
for ( int i = n ; i < z ; i ++ ) ret . push_back ( a [ i ]);
}
n -= z ;
if ( n < 0 ) {
k += n ;
n = 0 ;
}
a >>= z ;
}
FormalPowerSeries < mint > q ( d + 1 );
q [ 0 ] = 1 ;
for ( int i = 0 ; i < d ; i ++ ) q [ i + 1 ] = - c [ i ];
auto p = ( a * q ). pre ( d );
if ( n < a . size ()) {
p *= q . inv ( n + k );
p >>= n ;
} else {
p *= ( InverseShift ( q , n ) * q ). pre ( d );
p %= q ;
p *= q . inv ( k );
}
p . resize ( k );
if ( ret . empty ()) {
return p ;
} else {
for ( auto v : p ) ret . push_back ( v );
return ret ;
}
}
template < class mint >
mint LinearyRecurrentSequence ( FormalPowerSeries < mint > a , long long n ) {
if ( n < a . size ()) return a [ n ];
auto b = BerlekampMassey ( a );
int d = b . size () - 1 ;
a . resize ( d );
int z = 0 ;
while ( b . back () == 0 ) b . pop_back (), z ++ ;
a >>= z ;
n -= z ;
d -= z ;
return BostanMori (( a * b ). pre ( b . size ()), b , n );
}
/**
* @brief 線形漸化式用
* @docs docs/fps/linearly-recurrent-sequence.md
*/
#line 9 "verify/fps/LC_kth_term_of_linearly_recurrent_sequence.test.cpp"
int main () {
int d ;
ll k ;
in ( d , k );
fps a ( d ), c ( d );
in ( a , c );
out ( LinearyRecurrentSequence ( a , c , k ));
}