unittest
{
	assert( [ "2", "1 2 1 2 2 1" ].solve == 2 );
	assert( [ "3", "1 1 2 2 3 3 3 2 1" ].solve == 1 );
	assert( [ "3", "1 1 2 2 2 3 3 3 1" ].solve == 3 );
}



import std.algorithm;
import std.container;
import std.conv;
import std.range;
import std.stdio;
import std.typecons;

void main()
{
	stdin.byLineCopy.solve.writeln;
}

auto solve( Range )( Range input )
if( isInputRange!Range && is( ElementType!Range == string ) )
{
	auto n = input.front.to!( long );
	input.popFront;
	auto as = input.front.split.to!( long[] );
	as[] -= 1;
	
	// インラインDP
	// dp[ (iターン目) ][ 残したカード1枚目の数字 ][ 残したカード2枚目の数字 ] = 最大得点
	auto dp = new long[][]( n, n );
	foreach( ref dpp; dp ) dpp[] = long.min;					// -2000未満にしておけば絶対0以上にならないので無視できる
	auto z = 0L;												// 全体加算値
	auto mm = 0L;												// 全体最大値
	auto ms = new long[ n ];									// 部分最大値
	ms[] = long.min;
	auto queue = DList!( Tuple!( long, long, long ) )();		// 更新キュー
	
	// 最初のカード2枚を処理
	dp[ as[ 0 ] ][ as[ 1 ] ] = 0;
	dp[ as[ 1 ] ][ as[ 0 ] ] = 0;
	ms[ as[ 0 ] ] = 0;
	ms[ as[ 1 ] ] = 0;
	as.popFrontN( 2 );
	
	// 途中のカードを3枚ずつ処理
	foreach( i; 0L .. n - 1 )
	{
		if( as[ 0 ] == as[ 1 ] && as[ 1 ] == as[ 2 ] )
		{
			// 次の3枚が全て同値の場合
			// 全てのx,yについて dp[ i+1 ][ x ][ y ] = dp[ i ][ x ][ y ] +1 が最適になるので、全体加算値に+1する
			z++;
		}
		else
		{
			foreach( j; 0 .. 3 )
			{
				auto a = as[ j ];
				auto b = as[ ( j + 1 ) % 3 ];
				auto c = as[ ( j + 2 ) % 3 ];
				
				// 前ターンのx,yを両方を残す場合
				// dp[ i+1 ][ x ][ y ] = dp[ i ][ x ][ y ] になるので、処理不要
				
				// 前ターンのx,yの片方を残す場合
				// dp[ i+1 ][ x ][ a or b or c ] = dp[ i ][ x ][ ? ].reduce!max になるので、部分最大値を使って更新する
				// また、捨て札y,b,cが全て同値の場合は+1する
				foreach( x; 0L .. n )
				{
					auto v = ms[ x ];
					if( b == c ) v = max( v, dp[ x ][ b ] + 1 );
					queue.insertBack( tuple( x, a, v ) );
				}
				
				// 前ターンのx,yのどちらも残さない場合
				// dp[ i + 1 ][ a or b or c ][ a or b or c ] = dp[ i + 1 ][ ? ][ ? ].reduce!max になるので、全体最大値を使って更新する
				// また、捨て札x,y,cが全て同値の場合は+1する
				queue.insertBack( tuple( a, b, max( mm, dp[ c ][ c ] + 1 ) ) );
			}
		}
		
		// DPテーブルと最大値を更新
		while( !queue.empty )
		{
			auto x = queue.front[ 0 ];
			auto y = queue.front[ 1 ];
			auto v = queue.front[ 2 ];
			queue.removeFront;
			
			dp[ x ][ y ] = max( dp[ x ][ y ], v );
			dp[ y ][ x ] = max( dp[ y ][ x ], v );
			ms[ x ] = max( ms[ x ], v );
			ms[ y ] = max( ms[ y ], v );
			mm = max( mm, v );
		}
		as.popFrontN( 3 );
	}
	
	// 最後のカード1枚を処理
	return max( mm, dp[ as[ 0 ] ][ as[ 0 ] ] + 1 ) + z;
}
