hdu 5009 离散化+链表+dp

来源:互联网 发布:egd网络黄金最新报价 编辑:程序博客网 时间:2024/06/01 07:30

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 50007using 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