HDU - 5009 Paint Pearls dp + 链表 + 下界优化

传送门:HDU 5009

题意:给出n个连续的珠子,珠子有不同的颜色,现将其划分成任意多段,每一段的代价为该段中颜色种数的平方,问划分的最小总代价和是多少。

总思路:dp[i]代表处理到第i个珠子的最小花费,显然dp[i] = min(dp[j] + num[i][j] * num[i][j])(0 < j <= i)   num[i][j]代表[j...i]区间内的颜色种数。n^2转移显然不能接受。

优化方法1:用双向链表维护珠子的颜色,使得任意时刻已经遍历过的珠子中每种颜色都只保存一个最新位置,每次遇到一个重复的颜色,就将该颜色前一个位置从链表中删除,然后利用双向链表维护dp数组,因为链表每个节点都代表该位置有一个新的颜色,因此可以避免很多无用操作,但这还不够,如果给出序列为1,2,3。。。。n,那么链表就毫无用处了,因此我们还要加一个下界优化:显然dp[n] <= n,因为最差情况每个珠子分一段,这时dp[n] == n。

代码:

#include<bits/stdc++.h>
#define ll long long
#define pi acos(-1)
#define MAXN 50010
#define inf 0x3f3f3f3f
using namespace std;
typedef pair<int,int>P;
int a[MAXN], val[MAXN];
int pre[MAXN], nxt[MAXN];
int last[MAXN], dp[MAXN]; 
int main()
{
	int n, m, id, cnt;
	while(cin >> n)
	{
		for(int i = 1; i <= n; i++)
		{
			scanf("%d", a + i);
			val[i] = a[i];
			pre[i] = i - 1;
			nxt[i] = i + 1;
			last[i] = 0;
			dp[i] = inf;
		}
		dp[0] = 0; pre[0] = -1;
		sort(val + 1, val + n + 1);
		m = unique(val + 1, val + n + 1) - val;
		for(int i = 1; i <= n; i++)
		{
			a[i] = lower_bound(val + 1, val + m, a[i]) - val;
			id = last[a[i]];
			if(id){
				pre[nxt[id]] = pre[id];
				nxt[pre[id]] = nxt[id];
			}
			last[a[i]] = i;
			cnt = 0;
			for(int j = pre[i]; ~j; j = pre[j])
			{
				cnt++;
				dp[i] = min(dp[i], dp[j] + cnt * cnt);
				if(cnt * cnt >= n) break;
			}
		}
		printf("%d\n", dp[n]);
	}
    return 0;
}


优化方法2:将连续的同样颜色的珠子缩成一个珠子(易证这样做不影响dp结果的正确性),然后再用下界进行剪枝就行了。代码详见:点击打开链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值