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