标签:
题意:
给你一个数组,每个值代表一种颜色,每次选一个区间涂颜色,代价是区间内颜色种类数的平方,涂完所有数组,问你最小代价是多少
题解:
设定dp[i]为前i个数的最小代价,
那么转移就是dp[i] = min{dp[j]+cal(j+1,i)^2} cal计算区间内颜色种类数
明显超时;
当你从i-1遍历到0去寻找那个最小dp[j]+cal(j+1,i)^2时,有些电视可以跳跃的,那就是在k~i-1里面出现过的,就可以跳过,这个用双向链表实现
还有一个优化:当向前遍历时,不同个数的平方已经超过单独涂色的值 即 cal(j+1,i)^2>i 直接跳出
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<algorithm> #include<map> using namespace std; const int N = 1e5+10, M = 2e2+11, inf = 2e9, mod = 1e9+7; int dp[N],a[N],pre[N],nex[N],n; map<int,int >mp; int main() { while(scanf("%d",&n)!=EOF) { mp.clear(); memset(dp,127,sizeof(dp)); for(int i=1;i<=n;i++)scanf("%d",&a[i]); for(int i=1;i<=n;i++)nex[i]=i+1,pre[i]=i-1; dp[0]=0,pre[0]=-1; for(int i=1;i<=n;i++) { if(!mp[a[i]]) mp[a[i]]=i; else { int id = mp[a[i]]; nex[pre[id]] = nex[id]; pre[nex[id]] = pre[id]; mp[a[id]] = i; } int num = 0; for(int j=pre[i];j!=-1;j=pre[j]) { num++; dp[i] = min(dp[i],dp[j]+num*num); if(num*num>i) break; } } printf("%d\n",dp[n]); } return 0; }
HDU 5009 Paint Pearls 双向链表优化DP
标签:
原文地址:http://www.cnblogs.com/zxhl/p/5657345.html