JZOJ.【NOIP2013模拟联考6】秀姿势(sugata)


 

 

思路:大水题

找出一个区间满足区间尽可能长,且科目数为k+1

则可删除k个科目剩下一个人数最多的科目,形成连续子序列

显而易见,用线段树维护,因为我只会线段树

 


 

实现方法:

暴力枚举head,tail区间

线段树维护科目数最大科目人数

删除原先的

假如区间的科目数<=K+1则插入

然后ANS=max(C[1]);


 

CODE

 

#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
map<int,int>to;
int a[1000005],n,m,c[1000005],head,tail,tot,ans,num[1000005];
void del(int l,int r,int k,int x)
{
    if(l==r)
    {
        c[k]--;
        if(c[k]==0)num[k]=0;
    }
    else
    {
        int mid=(l+r)/2;
        if(x<=mid)
        {
            del(l,mid,k*2,x);
        }
        else
        {
            del(mid+1,r,k*2+1,x);
        }
        c[k]=max(c[k*2],c[k*2+1]);
        num[k]=num[k*2]+num[k*2+1];
    }
}
void ins(int l,int r,int k,int x)
{
    if(l==r)
    {
        c[k]++;
        num[k]=1;
    }
    else
    {
        int mid=(l+r)/2;
        if(x<=mid)
        {
            ins(l,mid,k*2,x);
        }
        else
        {
            ins(mid+1,r,k*2+1,x);
        }
        c[k]=max(c[k*2],c[k*2+1]);
        num[k]=num[k*2]+num[k*2+1];
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        if(to[a[i]]==0)to[a[i]]=++tot;
    }
    head=0;tail=1;
    ins(1,tot,1,to[a[1]]);
    while(head<tail)
    {
        head++;
        if(head>1)del(1,tot,1,to[a[head-1]]);
        while(num[1]<=m+1&&tail<n)
        {
            ins(1,tot,1,to[a[++tail]]);
        }
        if(num[1]>m+1)del(1,tot,1,to[a[tail--]]);
        if(tail<=n)
        {
            ans=max(ans,c[1]);
        }
     }
     printf("%d",ans);
}

 

posted @ 2020-06-20 15:46  HYDcn666_JZOJ  阅读(200)  评论(0编辑  收藏  举报