DP - hdu5009 Paint Pearls

题目:

http://acm.hdu.edu.cn/showproblem.php?pid=5009


题意:

有一串珠子需要染色,允许每次染一段区间,代价为这段区间的颜色总数color^2,求最小代价


思路:

感觉就是DP,然而就是搞不出怎么DP给跪了

先提出一个基础的DP思路 dp[i] = min{dp[j]+num[j+1,i]^2},dp[i]代表[1,i]这段区间的代价,0<=j<i,num为对应区间的颜色总数,显然,这么构建状态转移方程的情况下时间复杂是O(n^2),需要优化

以第二组测试数据为例,dp[9] = min{dp[8] + 1, dp[7] + 4, dp[6]+ 9, dp[0] + 9},嗯...嗯?!中间的dp[54321]哪去了!!事实上,中间的d[6],dp[5],dp[4]..是不需要考虑的,回头看状态转移方程,事实上这么转移是将[j+1,i]视为一段区间进行全体染色,则dp[6]+9,代表dp[6] + 对颜色{2,3,4}进行区间染色,则无论是[1,9][2,9][3,9]..[6,9]这些区间都是对颜色{2,3,4}进行区间染色,代价相同没有考虑的必要,直接跳到dp[0]的状态进行判断

因此,可以发现,每种颜色只要保留最后出现的位置即可,实现方式为数组模拟双向链表,具体看代码,反正也不长……


代码:

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <map>
using namespace std;
const int MAXINT = 0x7FFFFFFF;
const int MAXSIZE = 5*1e4 + 100;

int dp[MAXSIZE];
int pre[MAXSIZE];
int nxt[MAXSIZE];
int arr[MAXSIZE];
map<int, int> M;


int main(){
    int n;
    while (scanf("%d",&n)!=EOF){
        for (int i=1;i<=n;++i){
            scanf("%d",arr+i);
            pre[i] = i-1;
            nxt[i] = i+1;
        }
        pre[0] = -1;
        for (int i=1;i<=n;++i) dp[i] = MAXINT;
        dp[0] = 0;
        M.clear();
        for (int i=1;i<=n;++i){
            if (!M.count(arr[i])) M[arr[i]] = i;
            else {
                int t = M[arr[i]];
                nxt[pre[t]] = nxt[t];
                pre[nxt[t]] = pre[t];
                M[arr[i]] = i;
            }
            int cnt = 1;
            for (int j=pre[i];j!=-1;j=pre[j]){
                dp[i] = min(dp[j]+cnt*cnt, dp[i]);
                cnt++;
                if (cnt*cnt>n) break;
            }
        }
        printf("%d\n",dp[n]);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值