http://acm.hdu.edu.cn/showproblem.php?pid=5009
3 1 3 3 10 3 4 2 4 4 2 4 3 2 2
2 7
/** hdu 5009 dp+离散化 题目大意:为给定的一个区间的各个位置染色,已知要求的各个位置的目标颜色,每次染色的区间为连续的,可一次性染成目标颜色,每次的花费为这个区间上不同颜色的种类的平方,求最小花费 解题思路:定义dp[i]表示前i个染完色的最小花费。首先把连续的相同的数去掉,由于颜色1~1e9过于分散,离散化到1~n之间然后转移即可。有一个剪枝,见代码注释 */ #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <vector> using namespace std; const int N=50004; int dp[N],a[N],vis[N]; int n; struct note { int num,ip,rank; }kk[N]; int cmp1(note a,note b) { return a.num<b.num; } int cmp2(note a,note b) { return a.ip<b.ip; } int main() { while(~scanf("%d",&n)) { for(int i=1;i<=n;i++) scanf("%d",&a[i]); int k=1; kk[1].num=a[1]; kk[1].ip=1; for(int i=2;i<=n;i++) { if(a[i]!=a[i-1]) { kk[++k].num=a[i]; kk[k].ip=k; } } sort(kk+1,kk+k+1,cmp1); ///离散化============================= int cnt=2; kk[1].rank=1; for(int i=2;i<=k;i++) { if(kk[i].num!=kk[i-1].num) kk[i].rank=cnt++; else kk[i].rank=kk[i-1].rank; } ///=================================== sort(kk+1,kk+k+1,cmp2); for(int i=0;i<50004;i++) dp[i]=0xfffffff; memset(vis,0,sizeof(vis)); dp[0]=0;//这里是关键 dp[k]=k; vector<int>v; for(int i=0;i<k;i++) { cnt=0; for(int j=i+1;j<=k;j++) { if(!vis[kk[j].rank]) { cnt++; v.push_back(kk[j].rank); vis[kk[j].rank]=1; } if(dp[i]+cnt*cnt>=dp[k])//剪枝 break; dp[j]=min(dp[j],dp[i]+cnt*cnt); } for(int j=0;j<v.size();j++) vis[v[j]]=0; v.clear(); } printf("%d\n",dp[k]); } return 0; } /** 3 1 3 3 10 3 4 2 4 4 2 4 3 2 2 5 1 2 3 4 5 5 1 1 1 1 1 5 1 2 2 4 1 2 7 5 1 4 */