P3709 大爷的字符串题(莫队+离散化)
P3709 大爷的字符串题
题目背景
在那遥远的西南有一所学校,
/被和谐部分/
然后去参加该省省选虐场,
然后某蒟蒻不会做,所以也出了一个字符串题:
题目描述
给你一个字符串 \(a\),每次询问一段区间的贡献。
贡献定义:
每次从这个区间中拿出一个字符 \(x\) ,然后把 \(x\) 从这个区间中删除,直到区间为空。你要维护一个集合 \(S\)。
- 如果 \(S\) 为空,你 \(rp\) 减 \(1\)。
- 如果 \(S\) 中有一个元素不小于 \(x\),则你 \(rp\) 减 \(1\),清空 \(S\)。
- 之后将 \(x\) 插入 \(S\)。
由于你是大爷,平时做过的题考试都会考到,所以每次询问你搞完这段区间的字符之后最多还有多少 \(rp\)?\(rp\) 初始为 \(0\)。
询问之间不互相影响~
输入格式
第一行两个整数 \(n,m\),表示字符串长度与询问次数。
之后一行 \(n\) 个数,第 \(i\) 个整数表示给出的字符串的第 \(i\) 个字符 \(x_i\)。
接下来 \(m\) 行,每行两个整数 \(l, r\),表示一次询问的区间。
输出格式
对于每次询问,输出一行一个整数表示答案。
输入输出样例
输入 #1
3 3
3 3 3
3 3
3 3
3 3
输出 #1
-1
-1
-1
说明/提示
数据规模与约定
- 对于 \(10\%\) 的数据,是样例。
- 对于另外 \(10\%\) 的数据,保证 \(n,m \le 100;\)
- 对于另外 \(10\%\) 的数据,保证 \(n,m \le 10^3;\)
- 对于另外 \(10\%\) 的数据,保证 \(n,m \le 10^4;\)
- 对于另外 \(10\%\) 的数据,保证 \(n,m \le 10^5;\)
- 对于 \(100\%\) 的数据,\(1 \leq n,m \le 2 \times10^5,1 \leq a_i \leq 10^9,1 \leq l, r \leq n。\)
保证数据像某省省选 day1T2 一样 sb,大家尽情用暴力水过题吧!
没事,你只要在一个好学校,就算这题只能拿到 10 分,也可以进队了。
Solution
唔,其实这是道语文题,题目要求
给定一个区间,求区间内众数的出现次数
为啥是这样,我们看这样一个样例
111122233345
12345/123/123/1
可以发现我们把序列排成一段一段的递增序列是最优的,每进入新的一段,\(rp\)就会-1
求段落数也就是求出现次数最多的数的出现次数,因为后面段落出现的数一定也在前面的段落中出现过
用莫队求解
我们用\(cnt[x]\)表示\(x\)的出现次数,很明显在\(add()\)中\(ans=max(ans,cnt[x])\)
但是删除的时候,可能会遇到这样一个问题,当前的\(cnt[x]\)恰好就等于\(ans\),那我们能直接使\(ans--\)吗?不能!因为可能还有其他的\(cnt[y]\)也等于\(ans\),删掉一个\(x\)不足以改变我们的答案
所以现在还要开一个数组\(p[cnt]\),表示出现次数为\(cnt\)的数字有多少个
在\(remove()\)函数中,如果当前的\(cnt[x]==ans\)并且\(p[cnt[x]]==1\),我们才能使ans--
嗷,有一个细节,这道题的值域范围是\(10^9\),需要离散
Code
#include<bits/stdc++.h>
#define il inline
#define rg register
#define lol long long
#define in(i) (i=read())
using namespace std;
const int N=2e5+5;
int read() {
int ans=0,f=1; char i=getchar();
while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+(i^48),i=getchar();
return ans*f;
}
int n,m,k,block,ans;
int a[N],sum[N],cnt[N],p[N],b[N];
struct query{
int l,r,id,pos;
bool operator < (const query &a) const {
return pos==a.pos?r<a.r:pos<a.pos;
}
}t[N];
void add(int x) {
p[cnt[a[x]]]--;
cnt[a[x]]++;
p[cnt[a[x]]]++;
ans=max(ans,cnt[a[x]]);
}
void remove(int x) {
if(p[cnt[a[x]]]==1 && ans==cnt[a[x]]) ans--;
p[cnt[a[x]]]--;
cnt[a[x]]--;
p[cnt[a[x]]]++;
}
int main() {
in(n), in(m); block=3*sqrt(n);
for (rg int i=1;i<=n;i++) in(a[i]),b[i]=a[i];
sort(b+1,b+1+n); int len=unique(b+1,b+1+n)-b-1;
for (int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+len,a[i])-b;
for (rg int i=1,l,r;i<=m;i++) {
in(l), in(r);
t[i].l=l, t[i].r=r;
t[i].id=i;
t[i].pos=(l-1)/block+1;
}
sort(t+1,t+1+m);
for (rg int i=1,curl=1,curr=0;i<=m;i++) {
rg int l=t[i].l,r=t[i].r;
while(curl<l) remove(curl++);
while(curl>l) add(--curl);
while(curr<r) add(++curr);
while(curr>r) remove(curr--);
sum[t[i].id]=-ans;
}
for (rg int i=1;i<=m;i++) cout<<sum[i]<<endl;
}
http://www.cnblogs.com/real-l/