bzoj1584[Usaco2009 Mar]Cleaning Up 打扫卫生

本文介绍了一种解决清理问题的优化算法。通过维护不同状态的值,如最近出现位置、不同数字的数量等,实现了O(n*sqrt(n))的时间复杂度。算法关键在于如何有效地更新这些状态值,以达到最小化成本的目的。

/*
n*n的算法 比较容易想到 特判的好cena的 70分 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int a[40005],f[40005];
int main()
{
    //freopen("cleanup.in","r",stdin);
    //freopen("cleanup.out","w",stdout);
    int n,m,i,j,k;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        f[i]=i;
    }
    for(i=1;i<=n;i++)
    {
        bool p[40005]={0};
        int q=0;
        f[i]=f[i-1]+1;
        for(j=i;j>=1;j--)
        {
            if(p[a[j]]==0)
            {
                p[a[j]]=1;
                q++;
            }
            f[i]=min(f[i],f[j-1]+q*q);
            if(q*q>=i)break;
        }
    }
    printf("%d",f[n]);
    return 0;
}

 


/*
n*sqrt(n): 维护这么几个值 pos[j] 当前位置到向前的某个位置不同的数字个数为j 并且最靠左 pre[a[i]] a[i]最后一次出现的位置 cnt[j] pos[j]+1到i序列不同的数字个数 因为如果某个序列不同的数字个数>sqrt(n) 那么分成n段最优 所以研究i向前到m=sqrt(n)个不同的数字的区间 方程为f[i]=min(f[i],f[pos[j]]+j*j) 关键是维护好这几个值 */ #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define maxn 40010 using namespace std; int a[maxn],pre[maxn],cnt[maxn],f[maxn],pos[maxn]; int n,m; int main() { //freopen("cleanup.in","r",stdin); //freopen("cleanup.out","w",stdout); scanf("%d%d",&n,&m); m=sqrt(n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); f[i]=i; } memset(pre,-1,sizeof(pre)); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) if(pre[a[i]]<=pos[j])//当前序列里没有出现过 cnt[j]++;//个数++ pre[a[i]]=i;//更新a[i]最后一次出现的位置 for(int j=1;j<=m;j++) if(cnt[j]>j)//区间左端点右移 { int t=pos[j]+1; while(pre[a[t]]>t)t++;//知道移动的是不在当前区间里的数 pos[j]=t; cnt[j]--; } for(int j=1;j<=m;j++) f[i]=min(f[i],f[pos[j]]+j*j); } printf("%d\n",f[n]); return 0; }

 

转载于:https://www.cnblogs.com/yanlifneg/p/5470837.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值