Problem:
Score : 500 points

Problem Statement

We have a grid with H horizontal rows and W vertical columns. Let (i,j) denote the square at the i-th row from the top and the j-th column from the left.

The square (i, j) has two numbers A_{ij} and B_{ij} written on it.

First, for each square, Takahashi paints one of the written numbers red and the other blue.

Then, he travels from the square (1, 1) to the square (H, W). In one move, he can move from a square (i, j) to the square (i+1, j) or the square (i, j+1). He must not leave the grid.

Let the unbalancedness be the absolute difference of the sum of red numbers and the sum of blue numbers written on the squares along Takahashi's path, including the squares (1, 1) and (H, W).

Takahashi wants to make the unbalancedness as small as possible by appropriately painting the grid and traveling on it.

Find the minimum unbalancedness possible.

Constraints

2 \leq H \leq 80

2 \leq W \leq 80

0 \leq A_{ij} \leq 80

0 \leq B_{ij} \leq 80

All values in input are integers.

Input

Input is given from Standard Input in the following format:

H W
A_{11} A_{12} \ldots A_{1W}
:
A_{H1} A_{H2} \ldots A_{HW}
B_{11} B_{12} \ldots B_{1W}
:
B_{H1} B_{H2} \ldots B_{HW}

Output

Print the minimum unbalancedness possible.

Sample Input 1

2 2
1 2
3 4
3 4
2 1

Sample Output 1

0

By painting the grid and traveling on it as shown in the figure below, the sum of red numbers and the sum of blue numbers are 3+3+1=7 and 1+2+4=7, respectively, for the unbalancedness of 0.

Sample Input 2

2 3
1 10 80
80 10 1
1 2 3
4 5 6

Sample Output 2

2

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

using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using Debug = System.Diagnostics.Trace;
using SB = System.Text.StringBuilder;
using System.Numerics;
using static System.Math;
using Number = System.Int32;

namespace Program {
	public class Solver {
		Random rnd = new Random();
		public void Solve() {
			var n = ri;
			var m = ri;
			var a = Enumerate(n, x => new int[m]);
			var b = Enumerate(n, x => new int[m]);
			for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) a[i][j] = ri;
			for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) b[i][j] = ri;
			var c = Enumerate(n + 1, x => new int[m + 1]);
			for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) c[i][j] = Abs(a[i][j] - b[i][j]);
			var dp = new bool[n + 1, m + 1, 6500];
			dp[0, 0, c[0][0]] = true;
			for (int i = 0; i < n; i++)
				for (int j = 0; j < m; j++)
					for (int v = 0; v < 6400; v++) {
						if (!dp[i, j, v]) continue;
						dp[i + 1, j, v + c[i + 1][j]] = true;
						dp[i + 1, j, Abs(v - c[i + 1][j])] = true;
						dp[i, j + 1, v + c[i][j + 1]] = true;
						dp[i, j + 1, Abs(v - c[i][j + 1])] = true;
					}
			for (int i = 0; i < 6400; i++)
				if (dp[n - 1, m - 1, i]) {
					Console.WriteLine(i);
					return;
				}

		}
		const long INF = 1L << 60;
		static int[] dx = { -1, 0, 1, 0 };
		static int[] dy = { 0, 1, 0, -1 };
		int ri { get { return sc.Integer(); } }
		long rl { get { return sc.Long(); } }
		double rd { get { return sc.Double(); } }
		string rs { get { return sc.Scan(); } }
		public IO.StreamScanner sc = new IO.StreamScanner(Console.OpenStandardInput());

		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 public void Swap<T>(ref T a, ref T b) { var tmp = a; a = b; b = tmp; }
	}
}

#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, 50000000);
		t.Start();
		t.Join();
		//*/
		solver.Solve();
		Console.Out.Flush();
	}
}
#endregion
#region Ex
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)) { }
	}

	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 Set
/// <summary>
/// 要素の追加、削除、検索、取得が可能な集合を表します．
/// </summary>
/// <typeparam name="T">優先度付きキュー内の要素の型を指定します．</typeparam>
/// <remarks>内部的にはAVL木によって実装されています．</remarks>
public class Set<T> {
	Node root;
	readonly IComparer<T> comparer;
	readonly Node nil;
	/// <summary>
	/// 多重集合かどうかを表します．
	/// </summary>
	public bool IsMultiSet { get; set; }
	public Set(IComparer<T> comparer) {
		nil = new Node(default(T));
		root = nil;
		this.comparer = comparer;
	}
	public Set(Comparison<T> comaprison) : this(Comparer<T>.Create(comaprison)) { }
	public Set() : this(Comparer<T>.Default) { }
	/// <summary>
	/// 要素をコレクションに追加します．
	/// </summary>
	/// <remarks>この操作は計算量 O(log N) で実行されます．</remarks>
	public bool Add(T v) {
		return insert(ref root, v);
	}
	/// <summary>
	/// v が存在するならコレクションから削除します．
	/// </summary>
	/// <remarks>この操作は計算量 O(log N) で実行されます．</remarks>
	public bool Remove(T v) {
		return remove(ref root, v);
	}
	/// <summary>
	/// 0-indexed で index 番目の要素をコレクションから取得します．．
	/// </summary>
	/// <remarks>この操作は計算量 O(log N) で実行されます．</remarks>
	public T this[int index] { get { return find(root, index); } }
	public int Count { get { return root.Count; } }
	public void RemoveAt(int k) {
		if (k < 0 || k >= root.Count) throw new ArgumentOutOfRangeException();
		removeAt(ref root, k);
	}
	/// <summary>
	/// このコレクションに含まれる要素を昇順に並べて返します．
	/// </summary>
	/// <remarks>この操作は計算量 O(N) で実行されます．</remarks>
	public T[] Items {
		get {
			var ret = new T[root.Count];
			var k = 0;
			walk(root, ret, ref k);
			return ret;
		}
	}
	void walk(Node t, T[] a, ref int k) {
		if (t.Count == 0) return;
		walk(t.lst, a, ref k);
		a[k++] = t.Key;
		walk(t.rst, a, ref k);
	}

	bool insert(ref Node t, T key) {
		if (t.Count == 0) { t = new Node(key); t.lst = t.rst = nil; t.Update(); return true; }
		var cmp = comparer.Compare(t.Key, key);
		bool res;
		if (cmp > 0)
			res = insert(ref t.lst, key);
		else if (cmp == 0) {
			if (IsMultiSet) res = insert(ref t.lst, key);
			else return false;
		}
		else res = insert(ref t.rst, key);
		balance(ref t);
		return res;
	}
	bool remove(ref Node t, T key) {
		if (t.Count == 0) return false;
		var cmp = comparer.Compare(key, t.Key);
		bool ret;
		if (cmp < 0) ret = remove(ref t.lst, key);
		else if (cmp > 0) ret = remove(ref t.rst, key);
		else {
			ret = true;
			var k = t.lst.Count;
			if (k == 0) { t = t.rst; return true; }
			if (t.rst.Count == 0) { t = t.lst; return true; }


			t.Key = find(t.lst, k - 1);
			removeAt(ref t.lst, k - 1);
		}
		balance(ref t);
		return ret;
	}
	void removeAt(ref Node t, int k) {
		var cnt = t.lst.Count;
		if (cnt < k) removeAt(ref t.rst, k - cnt - 1);
		else if (cnt > k) removeAt(ref t.lst, k);
		else {
			if (cnt == 0) { t = t.rst; return; }
			if (t.rst.Count == 0) { t = t.lst; return; }

			t.Key = find(t.lst, k - 1);
			removeAt(ref t.lst, k - 1);
		}
		balance(ref t);
	}
	void balance(ref Node t) {
		var balance = t.lst.Height - t.rst.Height;
		if (balance == -2) {
			if (t.rst.lst.Height - t.rst.rst.Height > 0) { rotR(ref t.rst); }
			rotL(ref t);
		}
		else if (balance == 2) {
			if (t.lst.lst.Height - t.lst.rst.Height < 0) rotL(ref t.lst);
			rotR(ref t);
		}
		else t.Update();
	}

	T find(Node t, int k) {
		if (k < 0 || k > root.Count) throw new ArgumentOutOfRangeException();
		for (; ; )
		{
			if (k == t.lst.Count) return t.Key;
			else if (k < t.lst.Count) t = t.lst;
			else { k -= t.lst.Count + 1; t = t.rst; }
		}
	}
	/// <summary>
	/// コレクションに含まれる要素であって、 v 以上の最小の要素の番号を返します。
	/// </summary>
	/// <remarks>この操作は計算量 O(log N) で実行されます．</remarks>
	public int LowerBound(T v) {
		var k = 0;
		var t = root;
		for (; ; )
		{
			if (t.Count == 0) return k;
			if (comparer.Compare(v, t.Key) <= 0) t = t.lst;
			else { k += t.lst.Count + 1; t = t.rst; }
		}
	}
	/// <summary>
	/// コレクションに含まれる要素であって、 v より真に大きい、最小の要素の番号を返します。
	/// </summary>
	/// <remarks>この操作は計算量 O(log N) で実行されます．</remarks>
	public int UpperBound(T v) {
		var k = 0;
		var t = root;
		for (; ; )
		{
			if (t.Count == 0) return k;
			if (comparer.Compare(t.Key, v) <= 0) { k += t.lst.Count + 1; t = t.rst; }
			else t = t.lst;
		}
	}

	void rotR(ref Node t) {
		var l = t.lst;
		t.lst = l.rst;
		l.rst = t;
		t.Update();
		l.Update();
		t = l;
	}
	void rotL(ref Node t) {
		var r = t.rst;
		t.rst = r.lst;
		r.lst = t;
		t.Update();
		r.Update();
		t = r;
	}


	class Node {
		public Node(T key) {
			Key = key;
		}
		public int Count { get; private set; }
		public sbyte Height { get; private set; }
		public T Key { get; set; }
		public Node lst, rst;
		public void Update() {
			Count = 1 + lst.Count + rst.Count;
			Height = (sbyte)(1 + Math.Max(lst.Height, rst.Height));
		}
		public override string ToString() {
			return string.Format("Count = {0}, Key = {1}", Count, Key);
		}
	}
}
#endregion