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] );
}
}