洛谷 P3709 大爷的字符串题(莫队+贪心)

 

 题目其实是和这道题目一样的 https://www.luogu.com.cn/problem/P1997

题目中有一句话很重要将这段区间搞完后最多还会剩下多少 rp,对于题目给出的规则我们可以理解为

  1. 如果区间不为空,答案为 0
  2. 存在 a∈ S,如果 a>=x ,那么清空 S,插入 a
  3. 任意 a∈ S,如果 a<x,那么直接插入 a

规则可以理解为构造任意个严格单调上升子序列,但是​​​​​​​为了使最后的答案最大,我们要保持构造的子序列的数量尽可能少,举个例子:我们已经构造了如下三个子序列:

  1. cd
  2. aef
  3. b

但是他们可以变成一个,不满足数量最少的条件,但是区间中的任意数字我们都可以打乱顺序来构造,所以只有遇到相同元素的时候,才迫不得已将 rp-1,所以题意转化为求区间内的众数的大小 

下面简述算法实现过程,由于 a[] 的值过大,如果要处理众数必须要利用桶,所以我们先将他们离散化

在整个过程中应用莫队,但是莫队要维护两个值,一个是 x 出现的次数,另一个是出现次数为 x 一共有多少个

const int N=2e5+5;

    int n,m;
    int i,j,k;
    int a[N];
    int vis[N],now,ans[N],app[N];  //vis[x] x出现的次数,app[x]出现 x 次的数量
    struct Node
    {
        int l,r;
        int bel,id;
        void read(){ sdd(l,r); }
    }q[N];
    vector<int> v;

bool cmp(Node a,Node b)
{
    return a.bel==b.bel?a.r<b.r:a.l<b.l;
}

void mo()
{
    int block=sqrt(n);
    for(int i=1;i<=m;i++) q[i].id=i,q[i].bel=q[i].l/block+1;
    sort(q+1,q+1+m,cmp);
}

int getid(int x)
{
    return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}

void add(int pos)
{
    int x=a[pos];
    app[vis[x]]--;
    app[++vis[x]]++;
    now=max(now,vis[x]);
}

void del(int pos)
{
    int x=a[pos];
    if(now==vis[x] && app[vis[x]]==1) now--;
    app[vis[x]]--;
    app[--vis[x]]++;
}

int main()
{
    //IOS;
    while(~sdd(n,m)){
        for(int i=1;i<=n;i++) sd(a[i]),v.pb(a[i]);
        sort(v.begin(),v.end());
        v.erase(unique(v.begin(),v.end()),v.end());
        for(int i=1;i<=n;i++) a[i]=getid(a[i]);
        for(int i=1;i<=m;i++) q[i].read();
        mo();
        int l=1,r=0; now=0;
        for(int i=1;i<=m;i++){
            while(l>q[i].l) add(--l);
            while(r<q[i].r) add(++r);
            while(r>q[i].r) del(r--);
            while(l<q[i].l) del(l++);
            ans[q[i].id]=-now;
        }
        for(int i=1;i<=m;i++) pd(ans[i]);
    }
    PAUSE;
    return 0;
}

 

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页