/** * author: Sooh * created: 19.11.2021 21:18:29 **/ #include using namespace std; #if __has_include() #include namespace atcoder { namespace internal { constexpr long long safe_mod(long long x, long long m) { x %= m; if (x < 0) x += m; return x; } struct barrett { unsigned int _m; unsigned long long im; barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {} unsigned int umod() const { return _m; } unsigned int mul(unsigned int a, unsigned int b) const { unsigned long long z = a; z *= b; #ifdef _MSC_VER unsigned long long x; _umul128(z, im, &x); #else unsigned long long x = (unsigned long long)(((unsigned __int128)(z)*im) >> 64); #endif unsigned int v = (unsigned int)(z - x * _m); if (_m <= v) v += _m; return v; } }; constexpr long long pow_mod_constexpr(long long x, long long n, int m) { if (m == 1) return 0; unsigned int _m = (unsigned int)(m); unsigned long long r = 1; unsigned long long y = safe_mod(x, m); while (n) { if (n & 1) r = (r * y) % _m; y = (y * y) % _m; n >>= 1; } return r; } constexpr bool is_prime_constexpr(int n) { if (n <= 1) return false; if (n == 2 || n == 7 || n == 61) return true; if (n % 2 == 0) return false; long long d = n - 1; while (d % 2 == 0) d /= 2; for (long long a : {2, 7, 61}) { long long t = d; long long y = pow_mod_constexpr(a, t, n); while (t != n - 1 && y != 1 && y != n - 1) { y = y * y % n; t <<= 1; } if (y != n - 1 && t % 2 == 0) { return false; } } return true; } template constexpr bool is_prime = is_prime_constexpr(n); constexpr std::pair inv_gcd(long long a, long long b) { a = safe_mod(a, b); if (a == 0) return {b, 0}; long long s = b, t = a; long long m0 = 0, m1 = 1; while (t) { long long u = s / t; s -= t * u; m0 -= m1 * u; // |m1 * u| <= |m1| * s <= b auto tmp = s; s = t; t = tmp; tmp = m0; m0 = m1; m1 = tmp; } if (m0 < 0) m0 += b / s; return {s, m0}; } constexpr int primitive_root_constexpr(int m) { if (m == 2) return 1; if (m == 167772161) return 3; if (m == 469762049) return 3; if (m == 754974721) return 11; if (m == 998244353) return 3; int divs[20] = {}; divs[0] = 2; int cnt = 1; int x = (m - 1) / 2; while (x % 2 == 0) x /= 2; for (int i = 3; (long long)(i)*i <= x; i += 2) { if (x % i == 0) { divs[cnt++] = i; while (x % i == 0) { x /= i; } } } if (x > 1) { divs[cnt++] = x; } for (int g = 2;; g++) { bool ok = true; for (int i = 0; i < cnt; i++) { if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) { ok = false; break; } } if (ok) return g; } } template constexpr int primitive_root = primitive_root_constexpr(m); } // namespace internal } // namespace atcoder #include #include #include namespace atcoder { namespace internal { #ifndef _MSC_VER template using is_signed_int128 = typename std::conditional::value || std::is_same::value, std::true_type, std::false_type>::type; template using is_unsigned_int128 = typename std::conditional::value || std::is_same::value, std::true_type, std::false_type>::type; template using make_unsigned_int128 = typename std::conditional::value, __uint128_t, unsigned __int128>; template using is_integral = typename std::conditional::value || is_signed_int128::value || is_unsigned_int128::value, std::true_type, std::false_type>::type; template using is_signed_int = typename std::conditional<(is_integral::value && std::is_signed::value) || is_signed_int128::value, std::true_type, std::false_type>::type; template using is_unsigned_int = typename std::conditional<(is_integral::value && std::is_unsigned::value) || is_unsigned_int128::value, std::true_type, std::false_type>::type; template using to_unsigned = typename std::conditional< is_signed_int128::value, make_unsigned_int128, typename std::conditional::value, std::make_unsigned, std::common_type>::type>::type; #else template using is_integral = typename std::is_integral; template using is_signed_int = typename std::conditional::value && std::is_signed::value, std::true_type, std::false_type>::type; template using is_unsigned_int = typename std::conditional::value && std::is_unsigned::value, std::true_type, std::false_type>::type; template using to_unsigned = typename std::conditional::value, std::make_unsigned, std::common_type>::type; #endif template using is_signed_int_t = std::enable_if_t::value>; template using is_unsigned_int_t = std::enable_if_t::value>; template using to_unsigned_t = typename to_unsigned::type; } // namespace internal } // namespace atcoder #include #include #include #ifdef _MSC_VER #include #endif namespace atcoder { namespace internal { struct modint_base {}; struct static_modint_base : modint_base {}; template using is_modint = std::is_base_of; template using is_modint_t = std::enable_if_t::value>; } // namespace internal template * = nullptr> struct static_modint : internal::static_modint_base { using mint = static_modint; public: static constexpr int mod() { return m; } static mint raw(int v) { mint x; x._v = v; return x; } static_modint() : _v(0) {} template * = nullptr> static_modint(T v) { long long x = (long long)(v % (long long)(umod())); if (x < 0) x += umod(); _v = (unsigned int)(x); } template * = nullptr> static_modint(T v) { _v = (unsigned int)(v % umod()); } static_modint(bool v) { _v = ((unsigned int)(v) % umod()); } 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 { if (prime) { assert(_v); return pow(umod() - 2); } else { auto eg = internal::inv_gcd(_v, m); assert(eg.first == 1); return eg.second; } } 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; } private: unsigned int _v; static constexpr unsigned int umod() { return m; } static constexpr bool prime = internal::is_prime; }; template struct dynamic_modint : internal::modint_base { using mint = dynamic_modint; public: static int mod() { return (int)(bt.umod()); } static void set_mod(int m) { assert(1 <= m); bt = internal::barrett(m); } static mint raw(int v) { mint x; x._v = v; return x; } dynamic_modint() : _v(0) {} template * = nullptr> dynamic_modint(T v) { long long x = (long long)(v % (long long)(mod())); if (x < 0) x += mod(); _v = (unsigned int)(x); } template * = nullptr> dynamic_modint(T v) { _v = (unsigned int)(v % mod()); } dynamic_modint(bool v) { _v = ((unsigned int)(v) % mod()); } 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 += mod() - rhs._v; if (_v >= umod()) _v -= umod(); return *this; } mint& operator*=(const mint& rhs) { _v = bt.mul(_v, rhs._v); 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 { auto eg = internal::inv_gcd(_v, mod()); assert(eg.first == 1); return eg.second; } 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; } private: unsigned int _v; static internal::barrett bt; static unsigned int umod() { return bt.umod(); } }; template internal::barrett dynamic_modint::bt = 998244353; using modint998244353 = static_modint<998244353>; using modint1000000007 = static_modint<1000000007>; using modint = dynamic_modint<-1>; namespace internal { template using is_static_modint = std::is_base_of; template using is_static_modint_t = std::enable_if_t::value>; template struct is_dynamic_modint : public std::false_type {}; template struct is_dynamic_modint> : public std::true_type {}; template using is_dynamic_modint_t = std::enable_if_t::value>; } // namespace internal } // namespace atcoder using namespace atcoder; using mint = modint998244353; //using mint = modint1000000007; #endif #pragma region template using ll = long long; template using V = vector; #define rep(i,n) for(int i=0;i void view(T e){std::cerr << e;} template void view(pair e){std::cerr << "("; view(e.fi); std::cerr << ", "; view(e.se); std::cerr << ")";} template void view(const set &st){ std::cerr << "\n";for(const auto& e : st){view(e); std::cerr << " ";}} template void view(const map &mp){ std::cerr << "\n";for(const auto& [k, v]: mp){std::cerr << "("; view(k); std::cerr << ", "; view(v); std::cerr << ") ";}} template void view(const unordered_map &mp){ std::cerr << "\n";for(const auto& [k, v]: mp){std::cerr << "("; view(k); std::cerr << ", "; view(v); std::cerr << ") ";}} template void view(const std::vector& v){std::cerr << "\n";for(const auto& e : v){ view(e); std::cerr << " "; }} template void view(const std::vector >& vv){std::cerr << "\n";int cnt = 0;for(const auto& v : vv){cerr << cnt << "th : "; view(v); cnt++; std::cerr << std::endl;}} #else #define debug(var) 0 #endif ll power(ll a, ll p){ll ret = 1; while(p){if(p & 1){ret = ret * a;} a = a * a; p >>= 1;} return ret;} ll modpow(ll a, ll p, ll mod){ll ret = 1; while(p){if(p & 1){ret = ret * a % mod;} a = a * a % mod; p >>= 1;} return ret;} ll modinv(ll a, ll m) {ll b = m, u = 1, v = 0; while (b) {ll t = a / b ;a -= t * b; swap(a, b);u -= t * v; swap(u, v);}u %= m;if (u < 0) u += m;return u;} templatebool chmax(T &a, const K b) { if (abool chmin(T &a, const K b) { if (b struct Matrix{ std::vector> A; // ll modulo; Matrix(){} Matrix(int _n):A(_n, std::vector(_n, 0)){} Matrix(int _n, int _m):A(_n, std::vector(_m, 0)){} //Matrix(int _n, int _m, ll md):A(_n, std::vector(_m, 0)){modulo = md;} Matrix(std::vector> &_A){ A = _A;} int height()const{return A.size();} int width()const{return A[0].size();} void multiply_vector(std::vector &v){ assert(width() == v.size()); std::vector res(height()); for(int i = 0; i < height(); i++){ for(int j = 0; j < width(); j++){ res[i] += (A[i][j] * v[j]); //res[i] += (A[i][j] * v[j]) % modulo; //if(res[i] >= modulo) res[i] -= modulo; } } v.swap(res); return; } // the result will be in B std::pair gauss_jordan(Matrix &B){ int rank = 0; T ret = 1; B = Matrix(*this); int n = height(), m = width(); for(int col = 0; col < m; col++){ for(int i = rank; i < n; i++){ if(B[i][col] != 0){ if(i != rank) ret *= -1; swap(B[i], B[rank]); break; } } if(B[rank][col] == 0) continue; ret *= B[rank][col]; for(int j = m - 1; j >= col; j--) B[rank][j] /= B[rank][col]; for(int r = 0; r < n; r++){ if(r == rank || B[r][col] == 0) continue; for(int c = m - 1; c > col; c--) B[r][c] -= B[r][col] * B[rank][c]; B[r][col] = 0; } if(++rank == n) break; } return std::pair(rank, ret); } Matrix inv(){ // 存在しないなら単位行列を返す int n = height(), m = width(); assert(n = m); int rank = 0; Matrix B = Matrix(*this), C = identity(n); for(int col = 0; col < m; col++){ for(int i = rank; i < n; i++){ if(B[i][col] != 0){ std::swap(B[i], B[rank]); std::swap(C[i], C[rank]); break; } } if(B[rank][col] == 0) return identity(n); for(int j = 0; j < m; j++) C[rank][j] /= B[rank][col]; for(int j = m - 1; j >= col; j--) B[rank][j] /= B[rank][col]; for(int r = 0; r < n; r++){ if(r == rank || B[r][col] == 0) continue; for(int c = 0; c < m; c++) C[r][c] -= B[r][col]*C[rank][c]; for(int c = m - 1; c > col; c--) B[r][c] -= B[r][col]*B[rank][c]; B[r][col] = 0; } if(++rank == n) break; } return C; } Matrix LU_decomposition(){ // Lの対角部が1、LUの狭義下三角がL assert(height() == width()); Matrix LU = Matrix(*this); int n = height(); for(int k = 0; k < n; k++){ for(int i = k + 1; i < n; i++){ LU[i][k] /= LU[k][k]; } for(int i = k + 1; i < n; i++){ for(int j = k + 1; j < n; j++){ LU[i][j] -= LU[j][k] * LU[k][i]; } } } return LU; } T det(){ assert(height() == width()); Matrix B; auto[rank, ret] = gauss_jordan(B); if(rank < height()) return T(0); return ret; } Matrix identity(int n){ Matrix I(n); for(int i = 0; i < height(); i++) I[i][i] = 1; return I; } Matrix &operator+=(const Matrix &B){ int n = height(), m = width(); assert(n == B.height() && m == B.width()); for(int i = 0; i < n; i++) for(int j = 0; j < m; j++) (*this)[i][j] += B[i][j]; return (*this); } Matrix &operator-=(const Matrix &B){ int n = height(), m = width(); assert(n == B.height() && m == B.width()); for(int i = 0; i < n; i++) for(int j = 0; j < m; j++) (*this)[i][j] -= B[i][j]; return (*this); } Matrix &operator*=(const Matrix &B){ int n = height(), m = width(), l = B.width(); assert(m == B.height()); std::vector> C(n, std::vector(m, 0)); for(int i = 0; i < n; i++) for(int j = 0; j < l; j++){ for(int k = 0; k < m; k++){ C[i][j] += ((*this)[i][k] * B[k][j]); //C[i][j] += ((*this)[i][k] * B[k][j]) % modulo; //if(C[i][j] >= modulo) C[i][j] -= modulo; } } A.swap(C); return (*this); } Matrix &operator^=(long long k){ Matrix B = Matrix::identity(height()); // B.modulo = this->modulo; while(k){ if(k & 1) B *= *this; *this *= *this; k >>= 1; } A.swap(B.A); return (*this); } Matrix operator+(const Matrix &B)const{return (Matrix(*this) += B);} Matrix operator-(const Matrix &B)const{return (Matrix(*this) -= B);} Matrix operator*(const Matrix &B)const{return (Matrix(*this) *= B);} Matrix operator^(const long long k)const{return (Matrix(*this) ^= k);} inline std::vector &operator[](int k){ return A.at(k);} inline const std::vector &operator[](int k)const{ return A.at(k);} friend ostream &operator<<(ostream &os, Matrix &p){ size_t n = p.height(), m = p.width(); for(int i = 0; i < n; i++) { os << "["; for(int j = 0; j < m; j++) { os << p[i][j] << (j + 1 == m ? "]\n" : ","); } } return (os); } }; int main(){ cin.tie(nullptr); ios::sync_with_stdio(false); //cout << fixed << setprecision(20); ll n, m, t; cin >> n >> m >> t; V> G(n); Matrix A(n, n); rep(i,m){ int a, b; cin >> a >> b; A[a][b] = A[b][a] = 1; } A ^= t; V dp(n); dp[0] = 1; A.multiply_vector(dp); cout << dp[0].val() << endl; }