好题!
本来想用一般的方法瞎搞个线段树什么的。。。发现不行。。。
然后翻题解。
注意到最优答案不会超过n,所以维护b[]数组,b[j]表示b[j]+1.....i有j个不同的数。
复杂度n√n。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define maxn 40050 #define inf 1000000000 using namespace std; int n,m,regis[maxn],pre[maxn],a[maxn],b[maxn],f[maxn],top; void update(int x) { int lim=top; for (int i=1;i<=top;i++) if (b[i]<pre[x]) { lim=i-1; break; } for (int i=lim;i>=2;i--) b[i]=b[i-1]; if (lim) b[1]=x-1; } void dp(int x) { for (int i=1;i<=top;i++) f[x]=min(f[x],f[b[i]]+i*i); } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&a[i]); for (int i=1;i<=n;i++) { pre[i]=regis[a[i]]; regis[a[i]]=i; } top=sqrt(n); for (int i=1;i<=n;i++) f[i]=inf; for (int i=1;i<=n;i++) { update(i); dp(i); } printf("%d ",f[n]); return 0; }