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

目录:


题目:

单击查看题目


分析:

我们可以考虑离散化+单调队列
先对问题进行转化:我们找到一个区间 [ l , r ] ,区间内存在不超过 K + 1 种不同的数字,找到出现次数最多的数字(其余数字都可以被直接刷掉),则这种数字的出现次数就可用于更新答案。
那么根据数据范围 A i 10 9 ,我们就对 A i 离散化,用数组 c n t 统计当前数字 A i 出现的次数
维护一个单调队列,表示当前的合法区间 [ l , r ] ,每次将右边界右移,新元素加入队列,利用 c 计算区间内不同数字的种数 l e n ,若超过 K + 1 ,则将左边界左移,不断弹出队头的元素,直到 r e s K + 1 。每次对合法区间 [ l , r ] 统计答案。


代码:

#pragma GCC optimize("3")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
#define LL long long
using namespace std;
inline LL read() {
    LL d=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
    return d*f;
}
int a[100001],b[100001],ans,c[100001],q[100001];
int main()
{   
    int n=read(),k=read()+1;
    int m;
    for(int i=1;i<=n;i++) a[i]=b[i]=read();
    sort(b+1,b+1+n);
    m=unique(b+1,b+n+1)-b-1;
    for(int i=1;i<=n;i++)
      a[i]=lower_bound(b+1,b+m+1,a[i])-b;
    int w=0,t=0,len=0;
    for(int i=1;i<=n;i++)
    {
        if(!c[q[++w]=a[i]]++) len++;
        if(len>k) {while(--c[q[++t]]); len--;}
        ans=max(ans,c[a[i]]);
    }
    printf("%d",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35786326/article/details/81123665