/*
n*n的算法 比较容易想到 特判的好cena的 70分
*/
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int a[40005],f[40005];
int main()
{
//freopen("cleanup.in","r",stdin);
//freopen("cleanup.out","w",stdout);
int n,m,i,j,k;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
f[i]=i;
}
for(i=1;i<=n;i++)
{
bool p[40005]={0};
int q=0;
f[i]=f[i-1]+1;
for(j=i;j>=1;j--)
{
if(p[a[j]]==0)
{
p[a[j]]=1;
q++;
}
f[i]=min(f[i],f[j-1]+q*q);
if(q*q>=i)break;
}
}
printf("%d",f[n]);
return 0;
}
/*
n*sqrt(n):
维护这么几个值
pos[j] 当前位置到向前的某个位置不同的数字个数为j 并且最靠左
pre[a[i]] a[i]最后一次出现的位置
cnt[j] pos[j]+1到i序列不同的数字个数
因为如果某个序列不同的数字个数>sqrt(n) 那么分成n段最优
所以研究i向前到m=sqrt(n)个不同的数字的区间
方程为f[i]=min(f[i],f[pos[j]]+j*j)
关键是维护好这几个值
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define maxn 40010
using namespace std;
int a[maxn],pre[maxn],cnt[maxn],f[maxn],pos[maxn];
int n,m;
int main()
{
//freopen("cleanup.in","r",stdin);
//freopen("cleanup.out","w",stdout);
scanf("%d%d",&n,&m);
m=sqrt(n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
f[i]=i;
}
memset(pre,-1,sizeof(pre));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
if(pre[a[i]]<=pos[j])//当前序列里没有出现过
cnt[j]++;//个数++
pre[a[i]]=i;//更新a[i]最后一次出现的位置
for(int j=1;j<=m;j++)
if(cnt[j]>j)//区间左端点右移
{
int t=pos[j]+1;
while(pre[a[t]]>t)t++;//知道移动的是不在当前区间里的数
pos[j]=t;
cnt[j]--;
}
for(int j=1;j<=m;j++)
f[i]=min(f[i],f[pos[j]]+j*j);
}
printf("%d
",f[n]);
return 0;
}