传送门
dp妙题。
考虑到每个位置分一组才花费
n
n
n的贡献。
因此某一段不同的数的个数不能超过
s
q
r
t
(
n
)
sqrt(n)
sqrt(n),于是对于当前的位置
i
i
i我们记
p
o
s
[
j
]
pos[j]
pos[j]表示
p
o
s
[
j
]
+
1
pos[j]+1
pos[j]+1到
i
i
i恰好有
j
j
j个不同的数。
这样
f
[
i
]
f[i]
f[i]就可以从
p
o
s
[
j
]
pos[j]
pos[j]转移过来。
由于
p
o
s
pos
pos数组最多
s
q
r
t
(
n
)
sqrt(n)
sqrt(n)个因此时间复杂度
O
(
n
∗
s
q
r
t
(
n
)
)
O(n*sqrt(n))
O(n∗sqrt(n))
代码:
#include<bits/stdc++.h>
#define N 40005
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
int n,m,a[N],f[N],las[N],pos[N],cnt[N],tot=0;
int main(){
n=read(),m=read();
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;++i){
int x=read();
if(x!=a[tot])a[++tot]=x;
}
n=tot,m=sqrt(n),f[0]=0;
for(int i=1;i<=n;++i){
f[i]=0x3f3f3f3f;
for(int j=1;j<=m;++j)if(las[a[i]]<=pos[j])++cnt[j];
las[a[i]]=i;
for(int j=1;j<=m;++j){
if(cnt[j]>j){
int tmp=pos[j]+1;
while(las[a[tmp]]>tmp)++tmp;
pos[j]=tmp,--cnt[j];
}
f[i]=min(f[i],f[pos[j]]+j*j);
}
}
cout<<f[n];
return 0;
}