Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 3239 Accepted Submission(s): 1052


/* f[i]表示涂完前適个所化的最小代价 f[i]=min(f[j]+num(j+1,i)^2);{0<=j<i} 双向链表优化+剪枝后时间复杂度:O(n√n) */ #include<map> #include<cstdio> #include<iostream> using namespace std; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } const int N=1e5+5; int n,a[N]; int pre[N],nxt[N]; map<int,int>mp; int f[N]; int main(){ while(~scanf("%d",&n)){ mp.clear();fill(f,f+n+1,2e9);f[0]=0; for(int i=1;i<=n;i++) a[i]=read(); for(int i=0;i<=n;i++) pre[i]=i-1,nxt[i]=i+1; //双向链表删点好神奇 for(int i=1,tmp;i<=n;i++){ if(!mp.count(a[i])) mp[a[i]]=i; else{ tmp=mp[a[i]]; nxt[pre[tmp]]=nxt[tmp]; pre[nxt[tmp]]=pre[tmp]; mp[a[i]]=i; } for(int j=pre[i],cnt=0;~j;j=pre[j]){ cnt++; f[i]=min(f[i],f[j]+cnt*cnt); if(cnt*cnt>n) break; } } printf("%d\n",f[n]); } return 0; }
原文:http://www.cnblogs.com/shenben/p/6710938.html