原题链接
考察:线性dp
思路:
  一开始完全没想到dp,看了题目的算法标签才做出来()
  \(f[i][j]\)记录当前位是\(i\),符合要求的子序列上一位是\(j\)的最长长度.
\(dp\)转移: 找到上一位与\(a[i]\)相等的位置$k%

  1. \(k\)存在 \(f[i][j] = f[j][k]+1\)
  2. \(k\)不存在 \(f[i][j] = f[j][j]+1\) 最短是\(2\).

Code

#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
const int N = 4010,M = 1000010;
int a[N],n,f[N][N];
vector<int> v[M];
int find(int x,vector<int>& als)
{
	int l = 0,r = als.size()-1;
	while(l<r)
	{
		int mid = l+r+1>>1;
		if(als[mid]<x) l = mid;
		else r = mid-1;
	}
	if(als[r]<x) return r;
	return als.size();
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++) 
	{
		scanf("%d",&a[i]);
		v[a[i]].push_back(i);
		f[i][i] = 1;
	}
	int ans = min(n,2);
	for(int i=1;i<=n;i++)
	  for(int j=1;j<i;j++)
	  {
	  		int c = find(j,v[a[i]]);
	    	if(c==v[a[i]].size())
	    	{
	    		f[i][j] = max(f[j][j]+1,f[i][j]);
	    		ans = max(f[i][j],ans);
	    		continue;
			}
	    	int k = v[a[i]][c];
	    	f[i][j] = max(f[j][k]+1,f[i][j]);
	    	ans = max(f[i][j],ans);
	  }
	printf("%d\n",max(ans,1));
	return 0;
}