http://acm.hdu.edu.cn/showproblem.php?pid=5009
有一段序列,涂连续一段子序列的代价为该子序列出现不同数字个数的平方,求最小代价涂完整个序列。
ai有10^9,所以先进行离散化
复杂度有n^2,需要剪枝,就是如果答案大于了dp[n]就不用往后继续转移了,这样复杂度就变成了
#include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <string> #include <queue> #include <vector> #include<set> #include <iostream> #include <algorithm> using namespace std; #define RD(x) scanf("%d",&x) #define RD2(x,y) scanf("%d%d",&x,&y) #define clr0(x) memset(x,0,sizeof(x)) typedef long long LL; const int INF = 1000000009; int n,r,dp[50005]; struct node{ int rank,v,i; }p[50005]; bool vis[50005]; bool cmp(node a,node b) { return a.v < b.v; } bool _cmp(node a,node b) { return a.i < b.i; } int main() { while(~RD(n)){ for(int i = 1;i <= n;++i){ RD(p[i].v); p[i].i = i; } sort(p+1,p+n+1,cmp); p[1].rank = r = 0; for(int i = 2;i <= n;++i){ if(p[i].v != p[i-1].v) p[i].rank = ++r; else p[i].rank = r; } sort(p+1,p+n+1,_cmp); clr0(vis); vector <int> vt; for(int i = 0;i <= n;++i){ dp[i] = i; } for(int j = 0;j < n;++j){ for(int i = j+1;i <= n;++i){ if(!vis[ p[i].rank ]) vis[ p[i].rank ] = 1,vt.push_back(p[i].rank); int tmp = dp[j] + vt.size()*vt.size(); if(tmp > dp[n]) break; dp[i] = min(dp[i],tmp); } for(int i = 0;i < vt.size();i++) vis[vt[i]] = 0; vt.clear(); } cout<<dp[n]<<endl; } return 0; }