dp
首先暴力的dp式子: f[i]=min{f[j]+num(j+1,i)}
这样是n^2的
考虑优化:
代价是一段区间不同颜色的数量,
那么如果区间的颜色数量是相同的,更新长度更长的区间一定更优
那么可以用双向链表优化一下,当一个数在之前出现过的时候,就将之前出现过的位置删除掉
其实相当于离散化了一下,只保留了对答案有用的状态
除了这个优化,可以注意到,我们肯定不会选择颜色数量超过根n的区间,因为最坏的情况下也是每个位置单独染色,代价为n
链表实现的小细节注意一下~
pre[0]设为-1
所以时间复杂度上限为 n根n
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> #include<stack> #include<cmath> #include<map> using namespace std; typedef long long ll; const int maxn = 50010; int n; int f[maxn]; int a[maxn],pre[maxn],nxt[maxn]; map<int,int> mp; ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f;} int main(){ while(scanf("%d",&n)!=EOF){ for(int i=1;i<=n;i++){ scanf("%d",&a[i]); pre[i]=i-1; nxt[i]=i+1; } memset(f,0x3f,sizeof(f)); f[0]=0; pre[0]=-1; mp.clear(); for(int i=1;i<=n;i++){ if(mp[a[i]]==0) mp[a[i]]=i; else{ int id=mp[a[i]]; pre[nxt[id]]=pre[id]; nxt[pre[id]]=nxt[id]; mp[a[i]]=i; } int cnt=0; for(int j=pre[i];j!=-1;j=pre[j]){ ++cnt; if(cnt*cnt>i) break; f[i]=min(f[i],f[j]+cnt*cnt); } } printf("%d\n",f[n]); } return 0; }