题解 洛谷 P3709 【大爷的字符串题】

luogu's link

题意:

这题...题意是重点!!!作为一道语文题,这道题的题意使难度上升了很多(其实重点是因为我语文差/kk

给你一个字符串 (a) (其实不是字符串,就是一个数组),每次询问一段区间的贡献。

区间的贡献定义:

初始 (rp=0)

每次从这个区间中拿出一个字符 (x) (数),然后把 (x) 从这个区间中删除,直到区间为空。你要维护一个集合 (S)

  • 如果 (S) 为空,你 (rp-1)

  • 如果 (S) 中有一个元素大于等于 (x),则你 (rp-1),清空 (S)

  • 之后将 (x) 插入 (S)

要求使得 (rp) 最大。

数据范围:(1 leq n,m le 2 imes10^5)

Solution:

由这个数据范围及只需查询很容易想到 莫队。

题意看起来比较麻烦,我一开始也被搞蒙了,后经过大佬@快乐的疯烁及神仙同桌@子落楸枰指点,才懂。

举个栗子:

比如题目编号 1 2 3 4 5 6 7

难度分别为 1 2 2 3 3 3 3

要查询 1-4,2-5,3-6

手摸得知,答案为 -2,-2,-3

插入顺序:

查询点1:以编号为 1,2,4,3 顺序插入最优。

查询点2:以编号为 2,4,3,5 顺序插入最优。

查询点3:以编号为 3,4,5,6 顺序插入最优。

由此,我们可以发现两个结论:

  1. 答案正是查询区间众数(与P1997 faebdc 的烦恼一样,是双倍经验)

  2. 插入时我们并不是从左到右插的,而是先全部是不同大小的插入,所以后面查询的时候是要先改 (r),再改 (l) 的!!!(不然你会得到 (80) 的高分,我就是因为这个调了两个晚自修 /fad)。

Code:

代码就很简单了。


/*
 * @Author: FuTianyu 
 * @Date: 2020-11-05 18:07:14 
 * @Last Modified by: FuTianyu
 * @Last Modified time: 2020-11-05 20:06:21
 */
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define debug() puts("fty")
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define REP(i,a,b) for(int i=a;i>=b;i--)
/*
快读快输
*/
const int N=2e5+5;
int n,m,a[N],b[N],kc,kuai[N],tong[N],sum[N],ans,Ans[N];
/*
a_i表示原始数组,由于很大,需要离散化,b_i即为离散化后的数组.
tong_i表示第i个数在区间内出现的个数,sum_i表示区间内出现个数为i的个数.
*/
struct node{
    int l,r,id;
}cun[N];
bool cmp(node x,node y){
    return kuai[x.l]==kuai[y.l]?x.r<y.r:kuai[x.l]<kuai[y.l];
}
void del(int x){
    sum[tong[b[x]]]--;
    if(ans==tong[b[x]]&&sum[tong[b[x]]]==0) ans--;
    sum[--tong[b[x]]]++;
}
void add(int x){
    sum[tong[b[x]]]--;
    if(ans==tong[b[x]]) ans++;
    sum[++tong[b[x]]]++;
}
signed main(){
    n=read();
    m=read();
    kc=sqrt(n);
    FOR(i,1,n){
        a[i]=read();
        b[i]=a[i];
        kuai[i]=(i-1)/kc+1;
    }
    sort(a+1,a+1+n);
    int len=unique(a+1,a+1+n)-a-1;
    FOR(i,1,n) b[i]=lower_bound(a+1,a+1+len,b[i])-a;
    FOR(i,1,m){
        cun[i].l=read();
        cun[i].r=read();
        cun[i].id=i;
    }
    sort(cun+1,cun+1+m,cmp);
    int l=1,r=0;
    FOR(i,1,m){
        int L=cun[i].l;
        int R=cun[i].r;
        while(r>R) del(r--);
        while(r<R) add(++r);
        while(l<L) del(l++);          
        while(l>L) add(--l);              
        Ans[cun[i].id]=-ans;
    }
    FOR(i,1,m){
        write(Ans[i]);
        puts("");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/F-T-Y/p/Solution-Luogu-P3709.html