Problem:
Score : 1800 points

Problem Statement

We have an N \times M grid. The square at the i-th row and j-th column will be denoted as (i,j).
Particularly, the top-left square will be denoted as (1,1), and the bottom-right square will be denoted as (N,M).
Takahashi painted some of the squares (possibly zero) black, and painted the other squares white.

We will define an integer sequence A of length N, and two integer sequences B and C of length M each, as follows:

A_i(1\leq i\leq N) is the minimum j such that (i,j) is painted black, or M+1 if it does not exist.

B_i(1\leq i\leq M) is the minimum k such that (k,i) is painted black, or N+1 if it does not exist.

C_i(1\leq i\leq M) is the maximum k such that (k,i) is painted black, or 0 if it does not exist.

How many triples (A,B,C) can occur? Find the count modulo 998244353.

Notice

In this problem, the length of your source code must be at most 20000 B.
Note that we will invalidate submissions that exceed the maximum length.

Constraints

1 \leq N \leq 8000

1 \leq M \leq 200

N and M are integers.

Partial Score

1500 points will be awarded for passing the test set satisfying N\leq 300.

Input

Input is given from Standard Input in the following format:

N M

Output

Print the number of triples (A,B,C), modulo 998244353.

Sample Input 1

2 3

Sample Output 1

64

Since N=2, given B_i and C_i, we can uniquely determine the arrangement of black squares in each column.
For each i, there are four possible pairs (B_i,C_i): (1,1), (1,2), (2,2) and (3,0). Thus, the answer is 4^M=64.

Sample Input 2

4 3

Sample Output 2

2588

Sample Input 3

17 13

Sample Output 3

229876268

Sample Input 4

5000 100

Sample Output 4

57613837

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

// author: camypaper
using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using Debug = System.Diagnostics.Trace;
using SB = System.Text.StringBuilder;
using static System.Math;
using static System.Numerics.BigInteger;
using static Program.IO.Scanner;
using Number = System.Int64;

#region IO
namespace Program.IO {
	using System.IO;
	using System.Text;
	using System.Globalization;

	public class Printer : StreamWriter {
		public override IFormatProvider FormatProvider { get { return CultureInfo.InvariantCulture; } }
		public Printer(Stream stream) : base(stream, new UTF8Encoding(false, true)) { }
	}
	static public class Scanner {
		public static StreamScanner sc = new StreamScanner(Console.OpenStandardInput());
		public static int ri => sc.Integer();
		public static long rl => sc.Long();
		public static string rs => sc.Scan();
		public static double rd => sc.Double();
	}
	public class StreamScanner {
		public StreamScanner(Stream stream) { str = stream; }

		public readonly Stream str;
		private readonly byte[] buf = new byte[1024];
		private int len, ptr;
		public bool isEof = false;
		public bool IsEndOfStream { get { return isEof; } }

		private byte read() {
			if (isEof) return 0;
			if (ptr >= len) {
				ptr = 0;
				if ((len = str.Read(buf, 0, 1024)) <= 0) {
					isEof = true;
					return 0;
				}
			}
			return buf[ptr++];
		}

		public char Char() {
			byte b = 0;
			do b = read(); while ((b < 33 || 126 < b) && !isEof);
			return (char)b;
		}
		public string Scan() {
			var sb = new StringBuilder();
			for (var b = Char(); b >= 33 && b <= 126; b = (char)read()) sb.Append(b);
			return sb.ToString();
		}
		public string ScanLine() {
			var sb = new StringBuilder();
			for (var b = Char(); b != '\n' && b != 0; b = (char)read()) if (b != '\r') sb.Append(b);
			return sb.ToString();
		}
		public long Long() { return isEof ? long.MinValue : long.Parse(Scan()); }
		public int Integer() { return isEof ? int.MinValue : int.Parse(Scan()); }
		public double Double() { return isEof ? double.NaN : double.Parse(Scan(), CultureInfo.InvariantCulture); }
	}

}

#endregion

#region main
static class Ex {
	static public string AsString(this IEnumerable<char> ie) { return new string(ie.ToArray()); }
	static public string AsJoinedString<T>(this IEnumerable<T> ie, string st = " ") {
		return string.Join(st, ie);
	}
	static public void Main() {
		Console.SetOut(new Program.IO.Printer(Console.OpenStandardOutput()) { AutoFlush = true });
		var solver = new Program.Solver();
		var t = new System.Threading.Thread(solver.Solve, 100000000);
		t.Start();
		t.Join();
		//*/
		//solver.Solve();
		Console.Out.Flush();
	}
}
#endregion

namespace Program {
	public class Solver {
		Random rnd = new Random(0);
		public void Solve() {
			var n = ri;
			var m = ri;
			//if (n > 300) throw new Exception();
			var dp = new ModInt[n + 5];
			dp[0] = 1;
			var binom = new BinomialCoefficient(n + 500);
			/*
			var coef = Enumerate(n + 1, x => new ModInt[n + 1]);
			for (int i = 0; i <= n; i++)
				for (int ii = i; ii <= n; ii++) {
					ModInt v = 0;
					if (i == ii) {
						// v += 1; v += i * (i + 1) / 2; 
					}
					else {
						// v += binom[ii, i];
						// v += binom[ii - 1, i - 2] * (i - 1);

						if (i > 1) {
							//var u = (i - 2) * (i - 1) * binom.ifact[i - 1] * binom.fact[ii - 1] * binom.ifact[ii - i] / (ii - i + 2);
							//for (int d = 1; d < i; d++) v -= binom[ii - i + d - 1, d - 1] * (d - 1);
							//v -= u;
						}
						// v += binom[ii, i - 1] * 2;
						// for (int rem = 0; rem < i; rem++) v += binom[ii - i + rem, rem] * 2;
					}
					coef[i][ii] = v;
				}
			*/


			for (int j = 0; j < m; j++) {
				var next = new ModInt[n + 5];
				for (int i = 0; i <= n; i++) {
					next[i] += dp[i];
					next[i] += i * (i + 1) / 2 * dp[i];
					// for (int ii = i; ii <= n; ii++) next[ii] += coef[i][ii] * dp[i];
				}
				// binom[ii,i]
				{
					var a = new int[n + 5];
					for (int i = 0; i <= n; i++) a[i] = (int)(dp[i] * binom.ifact[i]).num;
					var b = new int[n + 5];
					for (int i = 1; i <= n; i++) b[i] = (int)binom.ifact[i + 2].num;
					var c = ModFFT.Convolute(a, b);
					for (int i = 1; i <= n; i++) next[i] += binom.fact[i + 2] * c[i];
				}
				dp = next;
			}
			ModInt ans = 0;
			for (int i = 0; i <= n; i++) ans += binom[n, i] * dp[i];
			// Debug.WriteLine(dp.AsJoinedString());
			Console.WriteLine(ans);

		}

		const long INF = 1L << 60;
		static int[] dx = { -1, 0, 1, 0 };
		static int[] dy = { 0, 1, 0, -1 };
		static T[] Enumerate<T>(int n, Func<int, T> f) {
			var a = new T[n]; for (int i = 0; i < a.Length; ++i) a[i] = f(i); return a;
		}
		static T[][] Enumerate<T>(int n, int m, Func<int, int, T> f) {
			return Enumerate(n, x => Enumerate(m, y => f(x, y)));
		}
		static public void Swap<T>(ref T a, ref T b) { var tmp = a; a = b; b = tmp; }
	}
}

#region ModInt
/// <summary>
/// [0,<see cref="Mod"/>) までの値を取るような数
/// </summary>
public struct ModInt {
	public const long Mod = 998244353;
	public long num;
	public ModInt(long n) { num = n; }
	public override string ToString() { return num.ToString(); }
	public static ModInt operator +(ModInt l, ModInt r) { return new ModInt(l.num + r.num < Mod ? l.num + r.num : l.num + r.num - Mod); }
	public static ModInt operator -(ModInt l, ModInt r) { return new ModInt(l.num + Mod - r.num < Mod ? l.num + Mod - r.num : l.num - r.num); }
	public static ModInt operator *(ModInt l, ModInt r) { return new ModInt(l.num * r.num % Mod); }
	public static ModInt operator /(ModInt l, ModInt r) { return l * Inverse(r); }
	public static implicit operator ModInt(long n) { return new ModInt(n); }
	public static ModInt Pow(ModInt v, long k) { return Pow(v.num, k); }
	public static ModInt Pow(long v, long k) {
		long ret = 1;
		for (k %= Mod - 1; k > 0; k >>= 1, v = v * v % Mod)
			if ((k & 1) == 1) ret = ret * v % Mod;
		return new ModInt(ret);
	}
	public static ModInt Inverse(ModInt v) { return Pow(v, Mod - 2); }
	public static ModInt Modulo(long v) { return new ModInt(((v % Mod) + Mod) % Mod); }
}
#endregion

#region Binomial Coefficient
public class BinomialCoefficient {
	public ModInt[] fact, ifact;
	public BinomialCoefficient(int n) {
		fact = new ModInt[n + 1];
		ifact = new ModInt[n + 1];
		fact[0] = 1;
		for (int i = 1; i <= n; i++)
			fact[i] = fact[i - 1] * i;
		ifact[n] = ModInt.Inverse(fact[n]);
		for (int i = n - 1; i >= 0; i--)
			ifact[i] = ifact[i + 1] * (i + 1);
		ifact[0] = ifact[1];
	}
	public ModInt this[int n, int r] {
		get {
			if (n < 0 || n >= fact.Length || r < 0 || r > n) return 0;
			return fact[n] * ifact[n - r] * ifact[r];
		}
	}
	public ModInt RepeatedCombination(int n, int k) {
		if (k == 0) return 1;
		return this[n + k - 1, k];
	}
}
#endregion
#region ModFFT
static class ModFFT {
	public const int MOD = 998244353;
	static readonly int[] roots;
	static ModFFT() {
		for (int i = 2; i * i <= MOD; i++) if (MOD % i == 0) throw new Exception();
		int t, p2;
		for (t = MOD - 1, p2 = 0; t % 2 == 0; t /= 2, p2++) ;
		if (p2 == 0) throw new Exception();
		roots = new int[p2 + 1];
		int s;
		for (s = 2; ; s++) if (ModPow(s, (MOD - 1) / 2) != 1) break;
		var pw = MOD - 1;
		for (int i = 0; i < p2; i++, pw /= 2)
			roots[i] = ModPow(s, pw);
	}
	static public int ModPow(long a, int k) {
		long ret = 1;
		for (; k > 0; a = (a * a) % MOD, k /= 2)
			if (k % 2 == 1) ret = (ret * a) % MOD;
		return (int)ret;
	}
	static void fft(int[] a, bool inv) {
		var n = a.Length;
		for (int i = 0, j = 1; j < n - 1; ++j) {
			for (int k = n >> 1; k > (i ^= k); k >>= 1) ;
			if (j < i) { var tmp = a[i]; a[i] = a[j]; a[j] = tmp; }
		}
		for (int p2 = 1, pow2 = 1; p2 < n; p2 *= 2, pow2++) {
			var w = roots[pow2];
			if (inv) w = ModPow(w, MOD - 2);
			for (int big = 0; big < n; big += 2 * p2) {
				int cur = 1;
				for (int small = big; small < big + p2; ++small) {
					int i = small;
					int j = small + p2;
					int u = a[i];
					int o = a[j];
					int v = (int)(o * (long)cur % MOD);
					a[i] = u + v;
					if (a[i] >= MOD) a[i] -= MOD;
					a[j] = u - v;
					if (a[j] < 0) a[j] += MOD;
					cur = (int)(cur * (long)w % MOD);
				}
			}

		}
	}
	static public int[] Convolute(int[] a, int[] b) {
		var k = 1;
		while (k < a.Length + b.Length - 1) k *= 2;
		var aa = new int[k]; Array.Copy(a, aa, a.Length);
		var bb = new int[k]; Array.Copy(b, bb, b.Length);
		fft(aa, false);
		fft(bb, false);
		var c = new int[k];
		for (int i = 0; i < k; i++)
			c[i] = (int)(Math.BigMul(aa[i], bb[i]) % MOD);
		fft(c, true);
		var inv = ModPow(k, MOD - 2);
		for (int i = 0; i < k; i++)
			c[i] = (int)(Math.BigMul(c[i], inv) % MOD);
		return c;
	}
}
#endregion