hdu 5009 离散化+链表+dp

1.这道题因为颜色给的数据范围大于数据总数,所以要对颜色进行离散化后再进行操作.

2.而这道题每次更新,可以用链表记录当前情况下每种颜色最靠近当前位置的所在位置后,因为最终花费是c*c,所以每一个所选区间的颜色数不能大于sqrt(区间长度),所以可以得到n*sqrt(n)复杂度算法的动态规划如下:

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

ac代码如下:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#define MAX 50007

using namespace std;
typedef long long LL;

int dp[MAX];
int c[MAX];
int a[MAX];
int pos[MAX];
int loc[MAX];

struct Node
{
    LL v,id;
    bool operator < ( const Node& a ) const
    {
        return v < a.v;
    }
}b[MAX];

struct List
{
    int v,next,pre;
}list[MAX];

int n,head,num;

void add ( int v )
{
    list[num].v = v;
    list[num].next = head;
    list[num].pre = -1;
    pos[v] = num;
    if ( head != -1 )
    {
        list[head].pre = num;
    }
    head = num++;
}

void erase ( int v )
{
    int x = list[pos[v]].pre;
    if ( x != -1)
        list[x].next = list[pos[v]].next;
    x = list[pos[v]].next;
    if ( x != -1 )
        list[x].pre = list[pos[v]].pre;
}

int main ( )
{
    while ( ~scanf ( "%d" , &n ) )
    {
        int cc = 0;
        a[0] = -1;
        for ( int i = 1 ; i <= n ; i++ )
        {
            scanf ( "%d" , &a[i] );
            if ( a[i] != a[i-1] )
            {
                 b[++cc].v = a[i];
                 b[cc].id = cc;
            }
        }
        sort ( b+1 , b+cc+1 );
        int color = 1;
        c[b[1].id]=1;
        for ( int i =2 ; i <= cc; i++ )
        {
            if ( b[i].v != b[i-1].v )
                color++;
            c[b[i].id] = color;
        }
        memset ( loc , -1 , sizeof ( loc ) );
        memset ( pos , -1 , sizeof ( pos ) );
        head = -1 , num = 0;
        dp[0] = 0;
        add ( 0 );
        int cnt,maxn;
        for ( int i = 1 ;i <= cc ; i++ )
        {
            if ( loc[c[i]] != -1 )
                erase( loc[c[i]] );
            loc[c[i]] = i;
            add ( i );
            cnt = 0;
            dp[i] = i;
            maxn = sqrt((double)i)+5;
            for ( int j = head ; j != -1 ; j=list[j].next )
            {
                int v = list[j].v;
                dp[i] = min ( dp[i] , dp[v] + cnt*cnt );
                cnt++;
                if ( cnt == maxn ) break;
            }
        }
        printf ( "%d\n" , dp[cc] );
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值