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: Runtime Error)

#[allow(non_snake_case)]
#[allow(unused)]
fn main() {
    proconio::input! {
        N: usize,
        A: [usize; 3 * N],
    }

    type Node = (usize, usize, usize);

    let update = |q: &mut std::collections::VecDeque<Node>, dp: &mut Vec<Vec<Vec<i32>>>, index: usize, x: usize, y: usize, a: usize, b: usize, c: usize, score: i32| {
        let xx = if x < y { x } else { y };
        let yy = if x < y { y } else { x };
        let newScore = score + if a == b && b == c { 1 } else { 0 };

        if newScore <= dp[index][xx][yy] { return; }
        dp[index][xx][yy] = std::cmp::max(dp[index][xx][yy], newScore);

        q.push_back((index, xx, yy));

        // eprintln!("-> index={}, ({}, {}), newScore={}", index, xx, yy, newScore);
    };

    let mut dp = vec![vec![vec![-1; N + 1]; N + 1]; N + 1];
    dp[0] = vec![vec![-1; N + 1]; N + 1];

    let mut q = std::collections::VecDeque::new();
    update(&mut q, &mut dp, 0, A[0], A[1], 1, 2, 3, 0);

    let mut ans = 0;

    while let Some((index, a1, a2)) = q.pop_front() {
        let a3 = A[index * 3 + 2];

        if index >= N - 1 {
            ans = std::cmp::max(ans, dp[index][a1][a2] + if a1 == a2 && a2 == a3 { 1 } else { 0 });
            continue;
        }

        let a4 = A[index * 3 + 3];
        let a5 = A[index * 3 + 4];

        let score = std::cmp::max(dp[index][a1][a2], dp[index][a2][a1]);

        // eprintln!("index={}, cards=({}, {}, {}, {}, {}), score={}", index, a1, a2, a3, a4, a5, score);

        update(&mut q, &mut dp, index + 1, a1, a2, a3, a4, a5, score);
        update(&mut q, &mut dp, index + 1, a1, a3, a2, a4, a5, score);
        update(&mut q, &mut dp, index + 1, a1, a4, a2, a3, a5, score);
        update(&mut q, &mut dp, index + 1, a1, a5, a2, a3, a4, score);

        update(&mut q, &mut dp, index + 1, a2, a3, a1, a4, a5, score);
        update(&mut q, &mut dp, index + 1, a2, a4, a1, a3, a5, score);
        update(&mut q, &mut dp, index + 1, a2, a5, a1, a3, a4, score);

        update(&mut q, &mut dp, index + 1, a3, a4, a1, a2, a5, score);
        update(&mut q, &mut dp, index + 1, a3, a5, a1, a2, a4, score);

        update(&mut q, &mut dp, index + 1, a4, a5, a1, a2, a3, score);
    }

    println!("{}", ans);
}