BZOJ 1584 打扫卫生

Posted on 2016-11-17 14:03  ziliuziliu  阅读(88)  评论(0编辑  收藏  举报

好题!

本来想用一般的方法瞎搞个线段树什么的。。。发现不行。。。

然后翻题解。

注意到最优答案不会超过n,所以维护b[]数组,b[j]表示b[j]+1.....i有j个不同的数。

复杂度n√n。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 40050
#define inf 1000000000
using namespace std;
int n,m,regis[maxn],pre[maxn],a[maxn],b[maxn],f[maxn],top;
void update(int x)
{
    int lim=top;
    for (int i=1;i<=top;i++)
        if (b[i]<pre[x])
        {
            lim=i-1;
            break;
        }
    for (int i=lim;i>=2;i--) b[i]=b[i-1];
    if (lim) b[1]=x-1;
}
void dp(int x)
{
    for (int i=1;i<=top;i++)
        f[x]=min(f[x],f[b[i]]+i*i);
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    for (int i=1;i<=n;i++)
    {
        pre[i]=regis[a[i]];
        regis[a[i]]=i;
    }
    top=sqrt(n);
    for (int i=1;i<=n;i++) f[i]=inf;
    for (int i=1;i<=n;i++)
    {
        update(i);
        dp(i);
    }
    printf("%d\n",f[n]);
    return 0;
}