hdu 5009 Paint Pearls

        题意:有一个序列,你需要给它上颜色。每次只能上一段连续的区间,费用是这个区间里颜色数的平方,问全部上色完成的最小花费是多少。

        思路:dp。首先是缩点,把相邻同色的合并起来,然后把颜色值离散化。完了就可以dp了。dp(i)是从头上色到i时的最小花费。dp(i)可以从dp(0)~dp(i-1)转移过来,还有就是需要极致地优化。。如果这一段的花费比到最后还高,就可以跳出了。


#include<iostream>
#include<cmath>
#include<queue>
#include<map>
#include<vector>
#include<algorithm>
#include<string.h>
#include<cstdio>

using namespace std;

struct node{
    int val;
    int idx;
    int rnk;
};
node a[50010];
bool vis[50010];
int dp[50010];
int vec[50010];     //数组优化,避免每次清空全部vis数组

bool cmp1(node n1,node n2){
    return n1.val<n2.val;
}

bool cmp2(node n1,node n2){
    return n1.idx<n2.idx;
}

int main(){
    int n;
    a[0].val=-1;
    while(~scanf("%d",&n)){
        int m=0;
        for(int i=1;i<=n;i++){
            int t;
            scanf("%d",&t);
            if(a[m].val!=t)m++;
            a[m].idx=m;
            a[m].val=t;
        }

        sort(a+1,a+m+1,cmp1);
        int k=0;
        for(int i=1;i<=m;i++){
            if(a[i].val!=a[i-1].val)k++;
            a[i].rnk=k;
        }
        sort(a+1,a+m+1,cmp2);
        for(int i=0;i<=m;i++)dp[i]=i;

        for(int i=0;i<m;i++){
            int cnt=0;
            int siz=0;
            for(int j=i+1;j<=m;j++){
                if(!vis[a[j].rnk]){
                    vec[siz++]=a[j].rnk;
                    vis[a[j].rnk]=1;
                    cnt++;
                }
                if(dp[i]+cnt*cnt>=dp[m])break;  //不可能取得最优解及时跳出
                dp[j]=min(dp[j],dp[i]+cnt*cnt);
            }
            for(int j=0;j<siz;j++){
                vis[vec[j]]=0;
            }
        }
        printf("%d\n",dp[m]);
    }
    return 0;
}


你可能感兴趣的:(2014西安网赛)