#include<bits/stdc++.h> 
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
#define f(x, m) for(auto x : m)
#define cpu() ios::sync_with_stdio(false); cin.tie(nullptr)
#define pb push_back
#define pii pair<int,int>
#define pll pair<ll, ll>
#define vi vector<int>
#define vl vector<ll>
#define vii vector<pair<int ,int>>
#define vll vector<pair<ll ,ll>>
#define all(v) v.begin(),v.end()
#define sor(a) sort( a.begin(), a.end() )
#define ros(a) sort( a.rbegin(), a.rend())
#define prec(n) fixed << setprecision(n)
#define ff first
#define ss second
#define print(x) for(auto it : x) cout << it << " ";
#define debug(x) cerr << #x << " is " << x << endl;

typedef long long ll;
using namespace std;
// using namespace __gnu_pbds;
#define dbg(args...){ string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); }
void err(istream_iterator<string> ) {cout << "NEXT\n"; }
template<typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args) {
cerr << *it << " = " << a << ", ";
err(++it, args...);
}
template<typename... T>
void rd(T& ... args){
   (( cin >> args), ...);
}
template<typename... T>
void ps(T ... args){
   ((cout << args << ' '), ...);
   cout << '\n';
}
//  mp.max_load_factor(0.25); 
// using ordered_set = tree<int, null_type, less<int>, rb_tree_tag,tree_order_statistics_node_update>;
const int MOD = 1e9 + 7, MOD1 = 998244353, MAX = 5e3 + 5;
const char nl = '\n';      
const ll INF = 2e18 + 5; 
int N, M; 
int dp[MAX][MAX];
int inv_[MAX];
int pot_[MAX];
ll pot(ll x, ll y){
   if(y == 0) return 1; 
   if(y & 1) return (pot(x, y - 1) * x) % MOD1;
   ll k = pot(x, y / 2);
   return (k * k) % MOD1;
}
ll inv(ll x){
   return pot(x, MOD1 - 2);
}
void add_self(int& x, int y){
   x += y; 
   if(x >= MOD1){
      x -= MOD1;
   }
}
int op(int m, int x){
   x = m - x;
   int xd1 = pot_[m];
   int xd2 = pot_[x];
   int gu = (xd1 - xd2); 
   if(gu < 0) gu += MOD1;
   gu = int(((ll)gu * inv_[m - x]) % MOD1);
   int th = pot_[m];
   th -= gu; 
   if(th < 0){
      th += MOD1;
   }
   return th;
}
void solve(){
   cin >> N >> M;
   for(int i = 1; i <= M; i++){
      dp[1][i] = 1;
      pot_[i] = 1;
   }
   for(int i = 2; i <= N; i++){
      int aux = 0;
      for(int j = 1; j <= M; j++){
         pot_[j] = int((ll(pot_[j]) * j) % MOD1);
         add_self(aux, dp[i - 1][j]);
      }
      for(int j = 1; j <= M; j++){
         add_self(dp[i][j], aux);
         add_self(dp[i][j], op(M, j));
      }
   }
   int ans = 0;
   for(int i = 1; i <= M; i++){
      add_self(ans, dp[N][i]);
   }
   cout << ans << "\n";
}
int main(){
   cpu();
   for(int i = 1; i < MAX; i++){
      inv_[i] = int(inv(i));
   }
   solve(); 

   return 0;
}
#include <bits/stdc++.h>
using namespace std;

template <typename T>
void print(const vector<vector<T>>& matrix, const string& name = "") {
  if (!name.empty()) cout << name << ": " << endl;
  for (const auto& row : matrix) {
    for (const auto& element : row) {
      cout << element << " ";
    }
    cout << endl;
  }
}

int main() {
  int L;
  cin >> L;

  // dp(i, j) = number of ways to cut prefix [:i] int j pieces
  const int64_t INFTY = 1e18;
  vector<vector<int64_t>> dpv(L, vector<int64_t>(13, 0));
  dpv[0][1] = 1;
  for (int i = 1; i < L; ++i) {
    for (int j = 1; j < dpv[i].size(); ++j) {
      // dpv[2][2] += dpv[1][2]

      // We don't cut.
      dpv[i][j] += dpv[i - 1][j];

      // We cut.
      dpv[i][j] += dpv[i - 1][j - 1];
    }
  }

  cout << dpv.back().back() << endl;
}