HDU 5009

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

题意:一个数列,每个点代表一种颜色,每次选一个区间覆盖,覆盖的代价是区间内颜色种类数的平方,直到覆盖整个数列,求最小花费

思路:首先合并颜色相同的点,接着离散化颜色,做dp,dp[i]表示取到位置i的最小花费,注意到答案最大值应该是合并后的数列长度,这是一个剪枝,为了避免每次循环memset vis数组,要把每次访问的颜色值记录在一个vector中,然后只清vector内的颜色清空vector 即可

这道题总的来说出的感觉比较怪,时间卡的很死,复杂度也怪怪的(具体复杂度不会算,但觉得如此dp应该tle才对),还要用一些非常奇怪的小技巧(加vector数组)。题不难,但是网赛时能当场AC的人真的是胆大又自信。

#include <iostream>

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <vector>

using namespace std ;



const int INF=0xfffffff ;



int n,dp[50005] ;



struct node 

{

    int num ;

    int id,rank ;

}kk[50005] ;

int a[50005] ;

int vis[50005] ;

int cmp1(node aa,node bb)

{

    return aa.num<bb.num ;

}

int cmp2(node aa,node bb)

{

    return aa.id<bb.id ;

}

int main()

{

    while(~scanf("%d",&n))

    {

        for(int i=1 ;i<=n ;i++)

        {

            scanf("%d",&a[i]) ;

        }

        int m=n ;

        for(int i=2 ;i<=n ;i++)

        {

            if(a[i]==a[i-1])

            {

                m-- ;

            }

        }

        int cnt=2 ;

        kk[1].id=1 ;kk[1].num=a[1] ;

        for(int i=2 ;i<=n ;i++)

        {

            if(a[i]!=a[i-1])

            {

                kk[cnt].id=cnt ;

                kk[cnt].num=a[i] ;

                cnt++ ;

            }

        }

        /*

        for(int i=1 ;i<=m ;i++)

        {

            printf("%d %d ",kk[i].num,kk[i].id) ;

        }

        printf("\n") ;

        */

        sort(kk+1,kk+1+m,cmp1) ;

        kk[1].rank=1 ;

        cnt=2 ;

        for(int i=2 ;i<=m ;i++)

        {

            if(kk[i].num!=kk[i-1].num)

            {

                kk[i].rank=cnt++ ;

            }

            else kk[i].rank=kk[i-1].rank ;

        }

        sort(kk+1,kk+1+m,cmp2) ;

        /*

        for(int i=1 ;i<=m ;i++)

        {

            printf("%d ",kk[i].rank) ;

        }

        printf("\n") ;

        */

        for(int i=0 ;i<50005 ;i++)

            dp[i]=INF ;

        dp[0]=0 ;

        dp[m]=m ;

        vector <int> v ;

        for(int i=0 ;i<m ;i++)

        {

            cnt=0 ;

            for(int j=i+1 ;j<=m ;j++)

            {

                if(!vis[kk[j].rank])

                {

                    v.push_back(kk[j].rank) ;

                    vis[kk[j].rank]=1 ;

                    cnt++ ;

                }

                if(dp[i]+cnt*cnt>=dp[m])break ;

                dp[j]=min(dp[j],dp[i]+cnt*cnt) ;

            }

            //memset(vis,0,sizeof(vis)) ;

            for(int j=0 ;j<v.size() ;j++)

                vis[v[j]]=0 ;

            v.clear() ;

        }

        printf("%d\n",dp[m]) ;

    }

    return 0 ;

}
View Code

 

你可能感兴趣的:(HDU)