Problem:
Score : 500 points

Problem Statement

There are K items placed on a grid of squares with R rows and C columns. Let (i, j) denote the square at the i-th row (1 \leq i \leq R) and the j-th column (1 \leq j \leq C). The i-th item is at (r_i, c_i) and has the value v_i.

Takahashi will begin at (1, 1), the start, and get to (R, C), the goal. When he is at (i, j), he can move to (i + 1, j) or (i, j + 1) (but cannot move to a non-existent square).

He can pick up items on the squares he visits, including the start and the goal, but at most three for each row. It is allowed to ignore the item on a square he visits.

Find the maximum possible sum of the values of items he picks up.

Constraints

1 \leq R, C \leq 3000

1 \leq K \leq \min(2 \times 10^5, R \times C)

1 \leq r_i \leq R

1 \leq c_i \leq C

(r_i, c_i) \neq (r_j, c_j) (i \neq j)

1 \leq v_i \leq 10^9

All values in input are integers.

Input

Input is given from Standard Input in the following format:

R C K
r_1 c_1 v_1
r_2 c_2 v_2
:
r_K c_K v_K

Output

Print the maximum possible sum of the values of items Takahashi picks up.

Sample Input 1

2 2 3
1 1 3
2 1 4
1 2 5

Sample Output 1

8

He has two ways to get to the goal:

Visit (1, 1), (1, 2), and (2, 2), in this order. In this case, the total value of the items he can pick up is 3 + 5 = 8.

Visit (1, 1), (2, 1), and (2, 2), in this order. In this case, the total value of the items he can pick up is 3 + 4 = 7.

Thus, the maximum possible sum of the values of items he picks up is 8.

Sample Input 2

2 5 5
1 1 3
2 4 20
1 2 1
1 3 4
1 4 2

Sample Output 2

29

We have four items in the 1-st row. The optimal choices are as follows:

Visit (1, 1) (1, 2), (1, 3), (1, 4), (2, 4), and (2, 5), in this order, and pick up all items except the one on (1, 2). Then, the total value of the items he picks up will be 3 + 4 + 2 + 20 = 29.

Sample Input 3

4 5 10
2 5 12
1 5 12
2 3 15
1 2 20
1 1 28
2 4 26
3 2 27
4 5 21
3 5 10
1 3 10

Sample Output 3

142

Solution in C# (.NET Core 3.1.201) (judge verdict: Wrong Answer)

using System;
using System.Collections;
using System.Collections.Generic;
//using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using static System.Math;
using static Math2;
using static Output;
using static Utils;

public class CP
{
	Scan sc;
	public void Solve()
	{
		sc = new Scan();
		bool multicases = false;
		var t = multicases ? sc.Int : 1;
		// var sw = new Stopwatch();
		// sw.Start();
		while (t-- > 0)
		{
			c1();
		}
		// sw.Stop();
		//Put(sw.ElapsedMilliseconds + "ms");
	}
	public void c1()
	{
		int r = sc.Int;
		int c = sc.Int;
		int k = sc.Int;
		long[][] grid = Enumerable.Range(0, r).Select(_ => new long[c]).ToArray();
		for (int i = 0; i < k; ++i)
		{
			grid[sc.Int - 1][sc.Int - 1] = sc.Long;
		}
		var dp = Enumerable.Range(0, r).Select(_ => Enumerable.Range(0, c).Select(__ => new long[4]).ToArray()).ToArray();
		dp[0][0][0] = 0;
		dp[0][0][1] = grid[0][0];
		for (int i = 0; i < r; ++i)
		{
			for (int j = 0; j < c; ++j)
			{
				for (int l = 0; l < 3; ++l)
				{
					//とる
					if (i != 0) dp[i][j][l + 1] = Max(dp[i][j][l + 1], dp[i - 1][j][l] + grid[i][j]);
					if (j != 0) dp[i][j][l + 1] = Max(dp[i][j][l + 1], dp[i][j - 1][l] + grid[i][j]);
				}
				for (int l = 0; l < 4; ++l)
				{
					//取らない
					if (i != 0) dp[i][j][l] = Max(dp[i][j][l], dp[i - 1][j][l]);
					if (j != 0) dp[i][j][l] = Max(dp[i][j][l], dp[i][j - 1][l]);
				}
			}
		}
		long ans = 0;
		ans = Max(ans, dp[r - 1][c - 1][0]);
		ans = Max(ans, dp[r - 1][c - 1][1]);
		ans = Max(ans, dp[r - 1][c - 1][2]);
		ans = Max(ans, dp[r - 1][c - 1][3]);
		Put(ans);
	}

}





public class PriorityQueue<T>
{
	List<T> _item;
	public int Count { get { return _item.Count; } }
	bool _isascend { get; set; }
	public T Peek { get { return _item[0]; } }
	Comparison<T> Comp;
	public PriorityQueue(bool IsAscend = true, IEnumerable<T> list = null) : this(Comparer<T>.Default.Compare, IsAscend, list) { }
	public PriorityQueue(Comparison<T> cmp, bool IsAscend = true, IEnumerable<T> list = null)
	{
		_item = new List<T>();
		_isascend = IsAscend;
		this.Comp = cmp;
		if (list != null)
		{
			_item.AddRange(list);
			Build();
		}
	}

	private int Compare(int i, int j) => (_isascend ? -1 : 1) * Comp(_item[i], _item[j]);
	private void Swap(int i, int j) { var t = _item[i]; _item[i] = _item[j]; _item[j] = t; }
	private int Parent(int i) => (i - 1) >> 1;
	private int Left(int i) => (i << 1) + 1;
	public T Enqueue(T val)
	{
		int i = _item.Count;
		_item.Add(val);
		while (i > 0)
		{
			int p = Parent(i);
			if (Compare(i, p) > 0)
				Swap(i, p);
			i = p;
		}
		return val;
	}
	private void Heapify(int index)
	{
		for (int i = index, j;
				(j = Left(i)) < _item.Count; i = j)
		{
			if (j != _item.Count - 1 && Compare(j, j + 1) < 0) j++;
			if (Compare(i, j) < 0)
				Swap(i, j);
		}
	}
	public T Dequeue()
	{
		T val = _item[0];
		_item[0] = _item[_item.Count - 1];
		_item.RemoveAt(_item.Count - 1);
		Heapify(0);
		return val;
	}
	private void Build()
	{
		for (var i = (_item.Count >> 1) - 1; i >= 0; i--)
			Heapify(i);
	}
	public bool Any() => Count > 0;
}
public class BinarySearch
{
	public static int Lower_Bound<T>(IList<T> Array, T Target)
	{
		return Lower_Bound<T>(Array, Target, Comparer<T>.Default.Compare);
	}
	public static int Lower_Bound<T>(IList<T> Array, T Target, Comparison<T> Comp)
	{
		var cmp = Comparer<T>.Create(Comp);
		var l = -1; //always ng
		var r = Array.Count(); //always ok
		while (r - l > 1)
		{
			var mid = l + (r - l) / 2;
			var res = cmp.Compare(Array[mid], Target);
			if (res >= 0) r = mid;
			else l = mid;
		}
		return r;
	}
	public static int Upper_Bound<T>(IList<T> Array, T Target)
	{
		return Upper_Bound<T>(Array, Target, Comparer<T>.Default.Compare);
	}
	public static int Upper_Bound<T>(IList<T> Array, T Target, Comparison<T> Comp)
	{
		var cmp = Comparer<T>.Create(Comp);
		var l = -1;
		var r = Array.Count;
		while (r - l > 1)
		{
			var mid = l + (r - l) / 2;
			var res = cmp.Compare(Array[mid], Target);
			if (res > 0) r = mid;
			else l = mid;
		}
		return r;
	}
	public static bool Contains<T>(IList<T> Arr, T Target)
	{
		return Contains<T>(Arr, Target, Comparer<T>.Default.Compare);
	}
	public static bool Contains<T>(IList<T> Arr, T Target, Comparison<T> Comp)
	{
		return (Upper_Bound(Arr, Target, Comp) - Lower_Bound(Arr, Target, Comp) > 0);
	}
}
public static class Math2
{
	public const int INF = 1 << 29;
	public const long INFL = 1L << 62;
	public const long MOD = 1000000007;
	public const long MOD2 = 998244353;

	public static long Power(long a, long b, long MOD = 1000000007) //i^N
	{
		long res = 1;
		while (b > 0)
		{
			if ((b & 1) != 0) res = res * a % MOD;
			a = a * a % MOD;
			b >>= 1;
		}
		return (res + 2 * MOD) % MOD;
	}
	public static long Power2(long a, long b) //i^N
	{
		long res = 1;
		while (b > 0)
		{
			if ((b & 1) != 0) res = res * a;
			a = a * a;
			b >>= 1;
		}
		return res;
	}
	public static BigInteger Power2BI(BigInteger a, BigInteger b) //i^N
	{
		BigInteger res = 1;
		while (b > 0)
		{
			if ((b & 1) != 0) res = res * a;
			a = a * a;
			b >>= 1;
		}
		return res;
	}
	public static long GCD(long a, long b)
	{
		if (a == 0) return b;
		while (b > 0)
		{
			var r = a % b;
			a = b;
			b = r;
		}
		return a;
	}
	public static long LCM(long a, long b) => (b / GCD(a, b)) * a;
	public static long Comb(long n, long r, int MOD = 1000000007)
	{
		if (r > n - r) r = n - r;
		long Nume = 1;
		long Deno = 1;

		if (r > n - r) r = n - r;
		for (long i = 1; i <= r; ++i)
		{
			Deno = (Deno * i) % MOD;
			Nume = Nume * (n - i + 1) % MOD;
		}
		return (Nume * inv(Deno)) % MOD;
	}
	public static long Comb2(long n, long r)
	{
		long Nume = 1;
		long Deno = 1;

		if (r > n - r) r = n - r;
		for (long i = 1; i <= r; ++i)
		{
			Deno *= i;
			Nume *= n - i + 1;
		}
		return Nume / Deno;
	}
	public static long inv(long x, int MOD = 1000000007)
	{
		return Power(x, MOD - 2, MOD);
	}
}
public static class Utils
{
	public static T[] sort<T>(this T[] a)
	{
		Array.Sort(a);
		return a;
	}
	public static long popcnt(long n)
	{
		n = (n & 0x55555555) + (n >> 1 & 0x55555555);
		n = (n & 0x33333333) + (n >> 2 & 0x33333333);
		n = (n & 0x0f0f0f0f) + (n >> 4 & 0x0f0f0f0f);
		n = (n & 0x00ff00ff) + (n >> 8 & 0x00ff00ff);
		n = (n & 0x0000ffff) + (n >> 16 & 0x0000ffff);
		return n;
	}
	public static int popcnt(BigInteger a)
	{
		int cnt = 0;
		while (a > 0)
		{
			if ((a & 1) == 1) ++cnt;
			a >>= 1;
		}
		return cnt;
	}
	public static void Swap<T>(ref T A, ref T B)
	{
		T x = A;
		A = B;
		B = x;
	}
	public static int DigitSum(string N)
	{

		int ret = 0;
		for (int i = 0; i < N.Length; ++i) ret += N[i] - '0';
		return ret;
	}
	public static string ConvertBase(char[] Num, int from, int to)
	{
		if (new string(Num) == "0") return "0";
		char[] sample = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
		BigInteger ten = 0;
		int power = 0;
		for (int i = Num.Length - 1; i >= 0; --i)
		{
			ten += (BigInteger)(Array.IndexOf(sample, Num[i])) * Power2BI(from, power);
			++power;
		}
		if (to == 10)
		{
			return ten.ToString();
		}
		var ret = new List<char>();
		if (to > 0)
		{
			while (ten > 0)
			{
				int r = (int)(ten % (to));
				ret.Add(sample[r]);
				ten /= to;
			}
		}
		else
		{
			while (ten != 0)
			{
				var r = (int)(ten % -to);
				if (r < 0) r -= to;
				ret.Add(sample[r]);
				ten -= r;
				ten /= -to;
				ten *= -1;
			}
		}
		ret.Reverse();
		return new string(ret.ToArray());
	}
	public static bool NextPermutation<T>(IList<T> lis, Comparison<T> cmp)
	{
		int n = lis.Count;
		int i = n - 1;
		while (i - 1 >= 0)
		{
			if (cmp(lis[i - 1], lis[i]) < 0) break;
			--i;
		}
		if (i == 0) return false;
		int j = i;
		while (j + 1 < n)
		{
			if (cmp(lis[i - 1], lis[j + 1]) > 0) break;
			++j;
		}
		var _q = lis[j];
		lis[j] = lis[i - 1];
		lis[i - 1] = _q;
		int k = i;
		int l = n - 1;
		while (k < l)
		{
			var _p = lis[k];
			lis[k] = lis[l];
			lis[l] = _p;

			++k;
			--l;
		}
		return true;
	}
	public static bool NextPermutation<T>(IList<T> lis) => NextPermutation(lis, Comparer<T>.Default.Compare);
}
class Program
{
	static void Main(string[] args)
	{
		var CP = new CP();
		CP.Solve();
	}
}
public static class Output
{

	public static void Put(string a) => Console.WriteLine(a);
	public static void Put(params object[] i) => Put(string.Join(" ", i));
	public static void Put<T>(IEnumerable<T> a) => Put(string.Join(" ", a));
	public static void PutV<T>(IEnumerable<T> a) { foreach (var z in a) Put(z); }
	public static void YN(bool i)
	{
		if (i) Put("Yes");
		else Put("No");
	}
}
public class Scan
{
	public static string Str => Console.ReadLine();
	public static bool IsTypeEqual<T, U>() => typeof(T).Equals(typeof(U));
	public static T ConvertType<T, U>(U a) => (T)Convert.ChangeType(a, typeof(T));
	public static T Cast<T>(string s)
	{
		if (IsTypeEqual<T, int>()) return ConvertType<T, int>(int.Parse(s));
		else if (IsTypeEqual<T, long>()) return ConvertType<T, long>(long.Parse(s));
		else if (IsTypeEqual<T, double>()) return ConvertType<T, double>(double.Parse(s));
		else if (IsTypeEqual<T, char>()) return ConvertType<T, char>(char.Parse(s));
		else if (IsTypeEqual<T, BigInteger>()) return ConvertType<T, BigInteger>(BigInteger.Parse(s));
		else if (IsTypeEqual<T, decimal>()) return ConvertType<T, decimal>(decimal.Parse(s));
		else return ConvertType<T, string>(s);
	}
	public static T[] Castarr<T>(string[] s)
	{

		var ret = new T[s.Length];
		int i = 0;
		if (IsTypeEqual<T, char>())
		{
			var list = new List<T>();
			foreach (var t in s)
			{
				foreach (var u in t)
				{
					list.Add(ConvertType<T, char>(char.Parse(u.ToString())));
				}
			}
			return list.ToArray();
		}
		foreach (var t in s)
		{
			if (IsTypeEqual<T, int>()) ret[i++] = ConvertType<T, int>(int.Parse(t));
			else if (IsTypeEqual<T, long>()) ret[i++] = ConvertType<T, long>(long.Parse(t));
			else if (IsTypeEqual<T, double>()) ret[i++] = ConvertType<T, double>(double.Parse(t));
			else if (IsTypeEqual<T, BigInteger>()) ret[i++] = ConvertType<T, BigInteger>(BigInteger.Parse(t));
			else ret[i++] = ConvertType<T, string>(t);
		}
		return ret;
	}
	Queue<string> q = new Queue<string>();
	void next() { var ss = Str.Split(' '); foreach (var item in ss) q.Enqueue(item); }
	public T cin<T>() { if (!q.Any()) next(); return Cast<T>(q.Dequeue()); }
	public T[] cinarr<T>() { return Castarr<T>(Str.Split(' ')); }
	public T[] cinarr<T>(int n) { var ret = new T[n]; for (int i = 0; i < n; ++i) ret[i] = cin<T>(); return ret; }
	public int Int => cin<int>();
	public long Long => cin<long>();
	public double Double => cin<double>();
	public char Char => cin<char>();
	public string String => cin<string>();
	public BigInteger BI => cin<BigInteger>();
	public int[] Intarr => cinarr<int>();
	public long[] Longarr => cinarr<long>();
	public double[] Doublearr => cinarr<double>();
	public char[] Chararr => cinarr<char>();
	public string[] Stringarr => cinarr<string>();
	public BigInteger[] BIarr => cinarr<BigInteger>();
	public void cin<T>(out T t) { t = cin<T>(); }
	public void mul<T, U>(out T t, out U u) { t = cin<T>(); u = cin<U>(); }
	public void mul<T, U, V>(out T t, out U u, out V v) { t = cin<T>(); u = cin<U>(); v = cin<V>(); }
	public void mul<T, U, V, W>(out T t, out U u, out V v, out W w) { t = cin<T>(); u = cin<U>(); v = cin<V>(); w = cin<W>(); }
	public void mul<T, U, V, W, X>(out T t, out U u, out V v, out W w, out X x) { t = cin<T>(); u = cin<U>(); v = cin<V>(); w = cin<W>(); x = cin<X>(); }
	public void mul<T, U, V, W, X, Y>(out T t, out U u, out V v, out W w, out X x, out Y y) { t = cin<T>(); u = cin<U>(); v = cin<V>(); w = cin<W>(); x = cin<X>(); y = cin<Y>(); }
	public void mul<T, U, V, W, X, Y, Z>(out T t, out U u, out V v, out W w, out X x, out Y y, out Z z) { t = cin<T>(); u = cin<U>(); v = cin<V>(); w = cin<W>(); x = cin<X>(); y = cin<Y>(); z = cin<Z>(); }
}