Loading

SP32900

还是板子题。

题目要求比较一个区间的众数的 \(k\) 倍与区间长度的大小,其实还是求出现次数最多的数的出现次数。

数据范围也比较温柔,那就普通莫队跑一下就好了。

只需要维护每个数的出现次数以及每种出现次数对应的数的个数,并判断区间伸缩在什么情况下对当前答案有影响即可。

其实比较好判断:

  • 当区间伸的时候,因为只加不删,答案不会更劣,所以不断取最大值即可;

  • 当区间缩的时候,要判断当前删除的这个数是不是唯一的众数,如果是则答案随其一起变小。

对于数据离散化后按上面的规则跑莫队,对每组询问跑完后判断一下当前答案的 \(k\) 倍与区间长度的大小即可。

#include<cmath>
#include<cstdio>
#include<bitset>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define maxn 500100
#define INF 0x3f3f3f3f
//#define int long long

using namespace std;

int n,m,len,L=2,R=1,tot,all,Ans; 
int a[maxn],ans[maxn],cnt[maxn],b[maxn],num[maxn];
struct question{int l,r,k,now;}q[maxn];
 
int read(){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
    return s*w;
}

bool cmp(question a,question b){
    return (a.l/len)^(b.l/len)?a.l<b.l:a.r<b.r;
}

void Add(int x){
    num[cnt[x]]--;
    num[++cnt[x]]++;
    Ans=max(Ans,cnt[x]);
} 

void Del(int x){
    num[cnt[x]]--;
    num[--cnt[x]]++;
    if(!num[cnt[x]+1]&&Ans==cnt[x]+1) Ans--;
}

signed main(){
    n=read();m=read();len=pow(n,2.0/3);
    for(int i=1;i<=n;i++) b[i]=a[i]=read();
    sort(b+1,b+n+1);all=unique(b+1,b+n+1)-b-1;
    for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+all+1,a[i])-b;
    for(int i=1,opt;i<=m;i++){
        q[i].l=read();q[i].r=read();
        q[i].k=read();q[i].now=i; 
    }
    sort(q+1,q+m+1,cmp); 
    for(int i=1;i<=m;i++){
        while(L<q[i].l) Del(a[L++]);
        while(L>q[i].l) Add(a[--L]);
        while(R<q[i].r) Add(a[++R]);
        while(R>q[i].r) Del(a[R--]);
        int lenth=q[i].r-q[i].l+1;
        ans[q[i].now]=(Ans*q[i].k>=lenth?1:0);
    }
    for(int i=1;i<=m;i++) printf(ans[i]?"YES\n":"NO\n");
    return 0;
}
posted @ 2021-04-25 16:38  KnightL  阅读(33)  评论(0编辑  收藏  举报