预处理找到每个位置每种颜色数向前最多延伸到哪个位置,然后就是dp不断向前找了,n*根号n,1890ms险过。。。
PS:比赛的时候脑子真秀逗,根本静不下来思考,这种题目的思路这么明确,努力方向这么显然,比赛时还tle了全场。。。
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <map>
using namespace std;
vector <int> ll[50005];
map <int,int> mp;
int dp[50005];
int n;
int v[50005];
int mark[50005];
int main()
{
while (cin>>n)
{
v[0]=-1;
mp.clear();
for (int i=1;i<=n;i++)
{
ll[i].clear();
mark[i]=0;
}
for (int i=1;i<=n;i++)
{
int a;
scanf("%d",&a);
if (a==v[i-1])
{
i--;
n--;
continue ;
}
v[i]=a;
}
int cnt=0;
for (int i=1;i<=n;i++)
{
if (mp[v[i]]==0)
{
cnt++;
mp[v[i]]=cnt;
v[i]=cnt;
}
else
v[i]=mp[v[i]];
}
for (int i=1;i<=n;i++)
{
ll[i].push_back(i);
int t=i-1;
if (mark[v[i]]==0)
mark[v[i]]=i;
for (int k=0;k<ll[t].size()&&(k*k)<n;k++)
{
if (ll[t][k]>mark[v[i]]&&ll[t][k+1]<=mark[v[i]])
continue ;
ll[i].push_back(ll[t][k]);
}
mark[v[i]]=i;
}
for (int i=1;i<=n;i++)
dp[i]=i;
dp[0]=0;
for (int i=1;i<=n;i++)
{
dp[i]=dp[i-1]+1;
for (int t=1;t<ll[i].size();t++)
{
int k=ll[i][t]-1;
dp[i]=min(dp[i],dp[k]+(t+1)*(t+1));
if ((t+1)*(t+1)>=dp[i])
break;
}
}
printf("%d\n",dp[n]);
}
}