这题一个是注意k*k所以k<=200实际上。然后注意如果dp时一个点加进去如果他的最近相同点也在哪个附近就不加一否则加一
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n, m;
int pos[40000],pre[40020],visit[40020];
int dp[2][210],tpos[2][210];
int main()
{
scanf("%d%d", &n, &m);
int k = 0;
for (int i = 0; i < n; i++)
{
int a;
scanf("%d", &a);
if (pos[k] != a)
{
pos[++k] = a;
}
}
for (int i = 1; i <= k; i++)
{
pre[i] = visit[pos[i]];
visit[pos[i]] = i;
}
for (int i = 1; i <= 200; i++)
dp[1][i] = 2000000000;
dp[1][1] = 1; tpos[1][1] = 1;
for (int i = 2; i <= k; i++)
{
for (int j = 1; j <= 200; j++)
dp[i & 1][j] = 2000000000;
tpos[i & 1][1] = i;
for (int j = 1; j <= 200; j++)
{
if (dp[(i - 1) & 1][j] == 2000000000)
continue;
if (dp[(i - 1) & 1][j]+1< dp[i & 1][1])
{
dp[i & 1][1] = dp[(i - 1) & 1][j] + 1;
}
if (pre[i] >= tpos[(i - 1) & 1][j])
{
if (dp[(i - 1) & 1][j] < dp[i & 1][j])
{
dp[i & 1][j] = dp[(i - 1) & 1][j];
tpos[i & 1][j] = tpos[(i - 1) & 1][j];
}
}
else
{
if (dp[(i - 1) & 1][j] + 2 * j + 1 < dp[i & 1][j + 1])
{
dp[i & 1][j + 1] = dp[(i - 1) & 1][j] + 2 * j + 1;
tpos[i & 1][j + 1] = tpos[(i - 1) & 1][j];
}
}
}
}
int ans = 2000000000;
for (int j = 1; j <= 200; j++)
{
ans = min(ans, dp[k & 1][j]);
}
printf("%d\n", ans);
}