HDU

来源:互联网 发布:北京淘宝美工培训2ds 编辑:程序博客网 时间:2024/05/17 04:46

传送门: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 0x3f3f3f3fusing 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结果的正确性),然后再用下界进行剪枝就行了。代码详见:点击打开链接

原创粉丝点击