ZOJ3790_Consecutive Blocks

给出一个数组,最多可以删除k个数,问能够获得的最长的一个数字连续段为多少?

把所有相同的数字都提取出来,保存取得每个数字需要删除的数字,然后二分枚举就可以了。

 

 

召唤代码君:

 

 

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define maxn 500200
using namespace std;

int a[maxn],b[maxn],first[maxn],next[maxn];
int Q[maxn],top,f[maxn];
bool vis[maxn];
int n,k,N,ans;

void go(int cur)
{
    vis[cur]=true;
    if (next[cur]!=-1){
        go(next[cur]);
        Q[top++]=cur-next[cur]-1;
    }
    else Q[top++]=0;
}

int main()
{
    while (scanf("%d%d",&n,&k)!=EOF){
        for (int i=0; i<n; i++){
            scanf("%d",&a[i]);
            b[i]=a[i];
        }
        sort(b,b+n);
        N=unique(b,b+n)-b;
        for (int i=0; i<n; i++) a[i]=lower_bound(b,b+N,a[i])-b+1;
        memset(first,-1,sizeof(int)*(n+3));
        for (int i=0; i<n; i++) next[i]=first[a[i]],first[a[i]]=i;
        memset(vis,false,sizeof(bool)*(n+2));
        ans=0;
        for (int i=n-1; i>=0; i--)
            if (!vis[i]){
                top=0;
                go(i);
                for (int j=1; j<top; j++) Q[j]+=Q[j-1];
                for (int pos=0; pos<top; pos++){
                    if (Q[top-1]-Q[pos]<=k){
                        ans=max(ans,top-pos);
                        break;
                    }

                    int l=pos,r=top-1,mid;
                    while (l<r){
                        mid=(l+r+1)/2;
                        if (Q[mid]-Q[pos]>k) r=mid-1;
                            else l=mid;
                    }
                    ans=max(ans,l-pos+1);
                }
            }
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2014-08-03 18:49  092000  阅读(325)  评论(0编辑  收藏  举报