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++ (GCC 9.2.1) (judge verdict: Time Limit Exceeded)

#ifdef mmlang_source_25_lines

R, C, K = inputInt(), inputInt(), inputInt()
rcv[:K] = inputInt() - 1, inputInt() - 1, inputInt()
rcv.sort()
V[:R][:C] = 0
for r, c, v in rcv:
    V[r][c] = v
D[:R][:C][:4] = 0LL
@memo
def solve(r, c, i)->int64:
    ret = 0LL
    if 1 <= i:
        ret >?= V[r][c]
    if 1 <= r:
        if i == 1:
            ret >?= solve(r - 1, c, : 4) + V[r][c]
        elif i == 0:
            ret >?= solve(r - 1, c, : 4)
    if 1 <= c:
        if 1 <= i:
            ret >?= solve(r, c - 1, i - 1) + V[r][c]
        ret >?= solve(r, c - 1, i)
    return ret
ans = 0
ans >?= solve(R - 1, C - 1, : 4)
print(ans)

#endif

//#define NDEBUG

#include <cassert>
#include <vector>
#include <deque>
#include <string>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <cstring>

using namespace std;

typedef long long int64;typedef __int128 int128;const char*inputCLineOrWord(int mode){static char buf[2097152];static int bufLen=sizeof(buf);static int bufPos=sizeof(buf);static bool canReadFlag=true;static bool crFlag=false;static bool enterFlag=false;if(canReadFlag&&(enterFlag?bufLen<=bufPos:(int)sizeof(buf)<=bufPos+bufPos)){if(0<bufLen-bufPos){memmove(buf,buf+bufPos,bufLen-bufPos);bufLen-=bufPos;}else{bufLen=0;}char*result=fgets(buf+bufLen,sizeof(buf)-bufLen,stdin);canReadFlag=(result!=NULL);if(result!=NULL){int n=strlen(result);enterFlag=(n!=(int)sizeof(buf)-1-bufLen||(1<=bufLen+n&&buf[bufLen+n-1]=='\n'));bufLen+=n;}bufPos=0;}if(mode==0){int pos=bufPos;while(true){char c=buf[pos];if(c==32){buf[pos++]='\0';break;}else if(c==10){if(crFlag){crFlag=false;if(bufPos==pos){pos=++bufPos;continue;}}buf[pos++]='\0';break;}else if(c==13){crFlag=true;buf[pos++]='\0';break;}else if(c==0){break;}++pos;}const char*ret=buf+bufPos;bufPos=pos;while(true){char c=buf[bufPos];if(c==32||c==10||c==13){++bufPos;}else{break;}}return ret;}else if(mode==1){int pos=bufPos;while(true){char c=buf[pos];if(c==10){if(crFlag){crFlag=false;if(bufPos==pos){pos=++bufPos;continue;}}buf[pos++]='\0';break;}else if(c==13){crFlag=true;buf[pos++]='\0';break;}else if(c==0){break;}++pos;}const char*ret=buf+bufPos;bufPos=pos;if(crFlag){while(true){char c=buf[bufPos];if(c==13){++bufPos;crFlag=false;break;}else{break;}}}return ret;}else if(mode==2){return bufLen<=bufPos?NULL:buf+bufPos;}assert(false);return NULL;}const char*inputCWord(){return inputCLineOrWord(0);}int inputInt(){return atoi(inputCWord());}void print_unit(bool val){printf("%s",val?"true":"false");}void print_unit(char val){printf("%c",val);}void print_unit(int val){printf("%d",val);}void print_unit(unsigned int val){printf("%u",val);}void print_unit(size_t val){printf("%zd",val);}void print_unit(const void*val){printf("%p",val);}void print_unit(long long val){printf("%lld",val);}void print_unit(__int128 val){char buf[128];int idx=128;buf[--idx]='\0';bool sign=false;if(val<0){sign=true;val=-val;}if(val==0){buf[--idx]='0';}else while(val){buf[--idx]='0'+(val % 10);val /=10;}if(sign){buf[--idx]='-';}printf("%s",buf+idx);}void print_unit(double val){printf("%g",val);}void print_unit(const char*val){printf("%s",val);}void print_unit(const std::string&val){printf("%s",val.c_str());}template<class T>void print_unit(const std::vector<T>&val){printf("vec(%d) {",(int)val.size());for(int i=0;i<(int)val.size();++i){fputc(' ',stdout);print_unit(val[i]);}printf(" }");}
#define _print0()
#define _print1(e)print_unit(e)
#define _print2(e1,e2)_print1(e1),fputc(' ',stdout),_print1(e2)
#define _print3(e1,e2,e3)_print2(e1,e2),fputc(' ',stdout),_print1(e3)
#define _print4(e1,e2,e3,e4)_print2(e1,e2),fputc(' ',stdout),_print2(e3,e4)
#define _print5(e1,e2,e3,e4,e5)_print3(e1,e2,e3),fputc(' ',stdout),_print2(e4,e5)
#define _print6(e1,e2,e3,e4,e5,e6)_print3(e1,e2,e3),fputc(' ',stdout),_print3(e4,e5,e6)
#define _print7(e1,e2,e3,e4,e5,e6,e7)_print4(e1,e2,e3,e4),fputc(' ',stdout),_print3(e5,e6,e7)
#define _print8(e1,e2,e3,e4,e5,e6,e7,e8)_print4(e1,e2,e3,e4),fputc(' ',stdout),_print4(e5,e6,e7,e8)
#define _print9(e1,e2,e3,e4,e5,e6,e7,e8,e9)_print5(e1,e2,e3,e4,e5),fputc(' ',stdout),_print4(e6,e7,e8,e9)
#define _print10(e1,e2,e3,e4,e5,e6,e7,e8,e9,e10)_print5(e1,e2,e3,e4,e5),fputc(' ',stdout),_print5(e6,e7,e8,e9,e10)
#define _GET_PRINT_MACRO_NAME(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,NAME,...)NAME
#define print(...)_GET_PRINT_MACRO_NAME(__VA_ARGS__,_print10,_print9,_print8,_print7,_print6,_print5,_print4,_print3,_print2,_print1,_print0)(__VA_ARGS__),fputc('\n',stdout)
#define print0(...)_GET_PRINT_MACRO_NAME(__VA_ARGS__,_print10,_print9,_print8,_print7,_print6,_print5,_print4,_print3,_print2,_print1,_print0)(__VA_ARGS__)

// generated code (by mmlang) :

int64 solve(int r, int c, int i);

int R;
int C;
int K;
vector<tuple<int, int, int> > rcv;
vector<vector<int> > V;
vector<vector<vector<long long> > > D;
int64 ans;

int64 solve$origin(int r, int c, int i) {
    long long ret;
    ret = 0LL;
    if(1 <= i) {
        ret = max(ret, (long long)(V[r][c]));
    }
    if(1 <= r) {
        if(i == 1) {
            for(int $1=0, $e=4; $1<$e; ++$1) ret = max(ret, (long long)(solve(r - 1, c, $1) + V[r][c]));
        }
        else if(i == 0) {
            for(int $1=0, $e=4; $1<$e; ++$1) ret = max(ret, (long long)(solve(r - 1, c, $1)));
        }
    }
    if(1 <= c) {
        if(1 <= i) {
            ret = max(ret, (long long)(solve(r, c - 1, i - 1) + V[r][c]));
        }
        ret = max(ret, (long long)(solve(r, c - 1, i)));
    }
    return ret;
}
map<tuple<int, int, int>, int64> solve$memo;
int64 solve(int r, int c, int i) {
    auto it = solve$memo.find(tuple<int, int, int>(r, c, i));
    if(it!=solve$memo.end()) {
        return it->second;
    }
    auto ret = solve$origin(r, c, i);
    solve$memo[tuple<int, int, int>(r, c, i)] = ret;
    return ret;
}

int main() {
    {
        const auto & $c1 = inputInt();
        const auto & $c2 = inputInt();
        const auto & $c3 = inputInt();
        tie(R, C, K) = tuple<int, int, int>($c1, $c2, $c3);
    }
    {
        rcv.resize(max((int)rcv.size(), (int)K));
        for(int $1=0, $e=(0<=K ? K : (int)rcv.size()+K); $1<$e; ++$1) {
            const auto & $c1 = inputInt() - 1;
            const auto & $c2 = inputInt() - 1;
            const auto & $c3 = inputInt();
            rcv[$1] = tuple<int, int, int>($c1, $c2, $c3);
        }
    }
    sort(rcv.begin(), rcv.end());
    {
        V.resize(max((int)V.size(), (int)R));
        for(int $1=0, $e=(0<=R ? R : (int)V.size()+R); $1<$e; ++$1) {
            V[$1].resize(max((int)V[$1].size(), (int)C));
            for(int $2=0, $e=(0<=C ? C : (int)V[$1].size()+C); $2<$e; ++$2) V[$1][$2] = 0;
        }
    }
    for(const tuple<int, int, int> & $fr : rcv) { const int & r = get<0>($fr); const int & c = get<1>($fr); const int & v = get<2>($fr);
        V[r][c] = v;
    }
    {
        D.resize(max((int)D.size(), (int)R));
        for(int $1=0, $e=(0<=R ? R : (int)D.size()+R); $1<$e; ++$1) {
            D[$1].resize(max((int)D[$1].size(), (int)C));
            for(int $2=0, $e=(0<=C ? C : (int)D[$1].size()+C); $2<$e; ++$2) {
                D[$1][$2].resize(max((int)D[$1][$2].size(), (int)4));
                for(int $3=0, $e=(0<=4 ? 4 : (int)D[$1][$2].size()+4); $3<$e; ++$3) D[$1][$2][$3] = 0LL;
            }
        }
    }
    ans = 0;
    for(int $1=0, $e=4; $1<$e; ++$1) ans = max(ans, solve(R - 1, C - 1, $1));
    print(ans);
    return 0;
}