大爷的字符串题 莫队

大爷的字符串题 莫队

首先这不是一道字符串题。需要仔细研究题的性质,我们会发现答案即为区间众数的个数,因为我们可以将区间分为众数个递增数列,这样为最优。

所以问题转换为求区间众数个数。使用莫队。

#include <cstdio>
#include <algorithm>
#include <cmath>
#define MAXN 400020
using namespace std;
int ans,a[MAXN],cnt[MAXN],sum[MAXN];
inline void add(int x){
    --sum[cnt[a[x]]];
    ++cnt[a[x]];
    ++sum[cnt[a[x]]];
    ans=max(cnt[a[x]], ans);
}
inline void del(int x){
    --sum[cnt[a[x]]];
    if(cnt[a[x]]==ans&&sum[cnt[a[x]]]==0) --ans;
    --cnt[a[x]];
    ++sum[cnt[a[x]]];
}
struct nod{
    int l,r,qid,bid;
} q[MAXN];
bool cmp(const nod &a, const nod &b){
    return ((a.bid^b.bid)?a.l<b.l:((a.bid&1)?a.r<b.r:a.r>b.r));
}
struct pa{
    int val,pos;
} ta[MAXN];
bool cmp_pair(const pa &a, const pa &b){
    return a.val<b.val;
}
int n,m,blo,qres[MAXN];
int main(){
    freopen("testdata.in", "r", stdin);
    scanf("%d %d", &n, &m);
    for(int i=1;i<=n;++i) scanf("%d", &ta[i].val), ta[i].pos=i;
    sort(ta+1, ta+1+n, cmp_pair);
    int idx=0;
    a[ta[1].pos]=idx;
    for(int i=2;i<=n;++i){
        if(ta[i-1].val!=ta[i].val) ++idx;
        a[ta[i].pos]=idx;
    }
    blo=n/sqrt(m*2.0/3);
    for(int i=1;i<=m;++i){
        scanf("%d %d", &q[i].l, &q[i].r);
        q[i].qid=i;
        q[i].bid=q[i].l/blo;
    }
    sort(q+1, q+1+m, cmp);
    int l=1,r=1;ans=1;cnt[a[1]]=1;sum[1]=1;
    for(int i=1;i<=m;++i){
        while(l<q[i].l) del(l++);
        while(l>q[i].l) add(--l);
        while(r<q[i].r) add(++r);
        while(r>q[i].r) del(r--);
        qres[q[i].qid]=ans;
    }
    for(int i=1;i<=m;++i) printf("%d\n", -1*qres[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/santiego/p/11328910.html

时间: 2024-10-09 03:59:13

大爷的字符串题 莫队的相关文章

luogu P3709 大爷的字符串题

二次联通门 : luogu P3709 大爷的字符串题 /* luogu P3709 大爷的字符串题 莫队 看了半天题目 + 题解 才弄懂了要求什么... 维护两个数组 一个记录数字i出现了几次 一个记录出现了i次的有几个数.. */ #include <algorithm> #include <cstdlib> #include <cstdio> #include <cmath> #define Max 200090 void read (int &

【Luogu】P3709大爷的字符串题(莫队算法)

题目链接 语文题啊…… 看题解发现是让求区间中最多的数的个数,于是果断理解了一会题解……莫队套上完事. sum[i]表示i这个数出现的次数,cnt[i]表示出现i次的数有几个,然后乱搞搞……就好了 #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #include<cctype> #include<cmath> #define maxn 3

洛谷 P3709 大爷的字符串题

https://www.luogu.org/problem/show?pid=3709 题目背景 在那遥远的西南有一所学校 /*被和谐部分*/ 然后去参加该省省选虐场 然后某蒟蒻不会做,所以也出了一个字符串题: 题目描述 给你一个字符串a,每次询问一段区间的贡献 贡献定义: 每次从这个区间中随机拿出一个字符x,然后把x从这个区间中删除,你要维护一个集合S 如果S为空,你rp减1 如果S中有一个元素不小于x,则你rp减1,清空S 之后将x插入S 由于你是大爷,平时做过的题考试都会考到,所以每次询问

P3709 大爷的字符串题(50分)

题目背景 在那遥远的西南有一所学校 /*被和谐部分*/ 然后去参加该省省选虐场 然后某蒟蒻不会做,所以也出了一个字符串题: 题目描述 给你一个字符串a,每次询问一段区间的贡献 贡献定义: 每次从这个区间中随机拿出一个字符x,然后把x从这个区间中删除,你要维护一个集合S 如果S为空,你rp减1 如果S中有一个元素不小于x,则你rp减1,清空S 之后将x插入S 由于你是大爷,平时做过的题考试都会考到,所以每次询问你搞完这段区间的字符之后最多还有多少rp?rp初始为0 询问之间不互相影响~ 输入输出格

[P3709] 大爷的字符串题

Link: P3709 传送门 Solution: lxl出的语文题 其实转化一下就是求将当前区间最少拆分成多少个严格单调上升序列(可不连续) 再转化一下就是求区间内的众数个数 本来求众数的套路是主席树+二分 但此题不要求在线,用莫队同时维护$i$的出现次数$cnt[i]$和出现次数为$i$的数的个数$sum[i]$ 这样常规套路更新结果就好了 Code: #include <bits/stdc++.h> using namespace std; const int MAXN=5e5+10;

luogu P3709大爷的字符串题

lxl出的又一道毒瘤题,题目本身让人读不懂,然而实际上题面用一句话就可以总结: 给你n个数,m次询问区间[l,r]中众数的出现次数 然后就用普通的莫队就好啦~~(数据也没有那么毒瘤) #include<algorithm> #include<cmath> #include<cstdio> using namespace std; const int maxn = 200200; int pos[maxn], num[maxn]; int ans[maxn]; int f

大爷的字符串题

莫队水毒瘤题 出题人语文水平极高,题意理解一下 就是求区间众数出现次数(什么毒瘤题目) #include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 5211314; int a[maxn], pos[maxn], s[maxn],d[maxn]; int cnt[maxn],ans[maxn],lx,n,m; int re(){ int x=0,w=1;char ch=getchar(

[voj 1551]E - Pairs 2014年武汉大学邀请赛E题 莫队算法

题目大意 有n个数,m个查询,对于每个查询,询问指定区间,有多少个数对的绝对值小于等于2. 解题思路 莫队O^1.5 首先将询问离线处理左端点进行编号,每sqrt(n)个为一组 sort结构体 当左端点编号相同时,比较右端点大小.小的放在前面. 对于每组询问暴力处理,只需处理当前新加入(删除的数字在当前区间内有多少点和它的绝对值只差小于2即可) 唯一要注意的是加点是先更新答案再计数,删点是先计数器-1再更新答案 因为对于每个询问,左端点的修改量不超过sqrt(n) 右端点每一组最坏的复杂度是修改

(莫队算法)两题莫队算法统计数量的入门题

因为这两题差不多,而且比较简单,就放一起,做了这题,这种题目就是巨水的题了.随便写都行. CodeForces - 86D  Powerful array 题意: 多次查询数列中从L到R每个数字出现次数的平方乘这个数字的和. 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <cmath> 5 #include <map> 6 #includ