Problem:
Score : 600 points

Problem Statement

We have 3N cards arranged in a row from left to right, where each card has an integer between 1 and N (inclusive) written on it. The integer written on the i-th card from the left is A_i.

You will do the following operation N-1 times:

Rearrange the five leftmost cards in any order you like, then remove the three leftmost cards. If the integers written on those three cards are all equal, you gain 1 point.

After these N-1 operations, if the integers written on the remaining three cards are all equal, you will gain 1 additional point.

Find the maximum number of points you can gain.

Constraints

1 \leq N \leq 2000

1 \leq A_i \leq N

Input

Input is given from Standard Input in the following format:

N
A_1 A_2 \cdots A_{3N}

Output

Print the maximum number of points you can gain.

Sample Input 1

2
1 2 1 2 2 1

Sample Output 1

2

Let us rearrange the five leftmost cards so that the integers written on the six cards will be 2\ 2\ 2\ 1\ 1\ 1 from left to right.

Then, remove the three leftmost cards, all of which have the same integer 2, gaining 1 point.

Now, the integers written on the remaining cards are 1\ 1\ 1.

Since these three cards have the same integer 1, we gain 1 more point.

In this way, we can gain 2 points - which is the maximum possible.

Sample Input 2

3
1 1 2 2 3 3 3 2 1

Sample Output 2

1

Sample Input 3

3
1 1 2 2 2 3 3 3 1

Sample Output 3

3

Solution in Rust (1.42.0) (judge verdict: Wrong Answer)

#![allow(non_snake_case)]

use proconio::input;
use proconio::marker::Usize1;
use std::cmp;

fn upd(i: usize, j: usize, x: i64, dp: &mut Vec<Vec<i64>>, N: usize) {
    dp[i][j] = cmp::max(dp[i][j], x);
    dp[j][i] = cmp::max(dp[j][i], x);
    dp[N][i] = cmp::max(dp[N][j], x);
    dp[i][N] = cmp::max(dp[i][N], x);
    dp[N][j] = cmp::max(dp[N][j], x);
    dp[j][N] = cmp::max(dp[j][N], x);
    dp[N][N] = cmp::max(dp[N][N], x);
}
fn main() {
    input! {
        N: usize,
        A: [Usize1; 3 * N]
    }

    let mut ans = 0;
    let mut dp = vec![vec![std::i64::MIN; N + 1]; N + 1];
    upd(A[0], A[1], 0, &mut dp, N);
    for i in (2..(3 * N - 1)).step_by(3) {
        if A[i] == A[i + 1] && A[i + 1] == A[i + 2] {
            ans += 1;
            continue;
        }

        let mut q = Vec::new();
        for j in 0..3 {
            let x = A[i + j % 3];
            let y = A[i + (1 + j) % 3];
            let z = A[i + (2 + j) % 3];

            // 難関
            for a in 0..=N {
                let mut v = dp[a][N];
                if y == z {
                    v = cmp::max(v, dp[a][y] + 1);
                }
                q.push((a, x, v));
            }

            // 簡単
            let v = cmp::max(dp[N][N], dp[z][z] + 1);
            q.push((x, y, v));
        }

        for (a, b, v) in q {
            upd(a, b, v, &mut dp, N);
        }
    }

    let l = A[3 * N - 1];
    ans += cmp::max(dp[N][N], dp[l][l] + 1);
    println!("{}", ans);
}