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)

use std::fmt::Debug;
use std::str::FromStr;

pub struct TokenReader {
    reader: std::io::Stdin,
    tokens: Vec<String>,
    index: usize,
}

impl TokenReader {
    pub fn new() -> Self {
        Self {
            reader: std::io::stdin(),
            tokens: Vec::new(),
            index: 0,
        }
    }

    pub fn next<T>(&mut self) -> T
    where
        T: FromStr,
        T::Err: Debug,
    {
        if self.index >= self.tokens.len() {
            self.load_next_line();
        }
        self.index += 1;
        self.tokens[self.index - 1].parse().unwrap()
    }

    pub fn vector<T>(&mut self) -> Vec<T>
    where
        T: FromStr,
        T::Err: Debug,
    {
        if self.index >= self.tokens.len() {
            self.load_next_line();
        }
        self.index = self.tokens.len();
        self.tokens.iter().map(|tok| tok.parse().unwrap()).collect()
    }

    pub fn load_next_line(&mut self) {
        let mut line = String::new();
        self.reader.read_line(&mut line).unwrap();

        self.tokens = line
            .split_whitespace()
            .map(String::from)
            .collect();
        self.index = 0;
    }
}

fn choose(options: &mut Vec<usize>, one: &Vec<usize>, two: &Vec<usize>)
    -> (Vec<usize>, usize) {
    let n = one.len();
    let mut count = vec![0; n];
    options.iter().for_each(|&num| count[num] += 1);

    for &num in options.iter() {
        if count[num] >= 3 {
            let mut left = vec![];
            let mut seen = 0;
            for &x in options.iter() {
                if x != num || seen >= 3 {
                    left.push(x);
                }
                if x == num {
                    seen += 1;
                }
            }
            return (left, 1);
        }
    }

    options.sort_by_key(|&x| {
        -(if count[x] == 1 { two[x] } else { one[x] } as i32)
    });

    let mut left = vec![options[0]];

    if count[options[0]] == 1 {
        for i in 1..options.len() {
            if count[options[i]] == 1 {
                left.push(options[i]);
                break;
            }
        }
        if left.len() < 2 {
            left.push(options[1]);
        }
    } else {
        left.push(options[1]);
    }

    (left, 0)
}

fn solve(nums: &mut Vec<usize>) -> usize {
    nums.reverse();

    let n = nums.len() / 3;
    let mut one = vec![vec![0; n + 1]; nums.len()];
    let mut two = vec![vec![0; n + 1]; nums.len()];

    one[0][nums[0]] = 1;
    for i in 1..nums.len() {
        one[i] = one[i - 1].clone();
        two[i] = two[i - 1].clone();

        one[i][nums[i]] = i + 1;
        if one[i - 1][nums[i]] > 0 {
            two[i][nums[i]] = i + 1;
        }
    }

    let mut res = 0;
    while nums.len() >= 5 {
        let mut options = (0..5).map(|_| nums.pop().unwrap()).collect();
        let one = if nums.len() > 0 { one[nums.len() - 1].clone() } else { vec![0; n + 1] };
        let two = if nums.len() > 0 { two[nums.len() - 1].clone() } else { vec![0; n + 1] };
        let (mut left, points) = choose(&mut options, &one, &two);
        nums.append(&mut left);
        res += points;
    }

    res += if nums[0] == nums[1] && nums[1] == nums[2] { 1 } else { 0 };
    res
}

fn main() {
    let mut reader = TokenReader::new();
    let _n = reader.next::<usize>();
    let mut nums = reader.vector();

    let res = solve(&mut nums);
    println!("{}", res);
}