P3709 大爷的字符串题 题解
P3709 大爷的字符串题题解
题意
容易发现我们要尽量使取出的数是严格递增的。
所以一次性尽量多取几个数,确保取出的数是严格递增的。
答案就是取几次。
容易发现,区间中最多的数决定了这个答案,所以题目其实就是求区间众数的出现次数。
(说个题外话,翻译出来其实就是P1997 faebdc 的烦恼。)
一眼莫队。
\(1\le n,m\le 2\times 10^5\)。
取块长为 \(\sqrt n\),时间复杂度 \(O(n\sqrt n)\),可过。
思路
翻译出来之后就比较板了,用 \(\operatorname{cnt}\) 数组记录数 \(i\) 的个数,再用 \(\operatorname{sum}\) 记录每一个数出现次数的出现次数(什么玩意都)。
然后就很好维护了,维护的细节就不多说了,大家都会。
细节:
-
需要离散化
-
答案输出时要带个
-
号。
其他的就很简单了。
code
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cctype>
#include<vector>
using namespace std;
const int N=1e6+10;
inline int read(){int c=0,w=1;char ch=getchar();for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;for(;ch>='0'&&ch<='9';ch=getchar()) c=(c<<3)+(c<<1)+ch-48;return c*w;}
void print(int x){if(x>9) print(x/10);putchar(x%10+48);}
struct query
{
int l,r;
int id;
}q[N];
int pos[N],aa[N],cnt[N],sum[N],ans[N];//cnt记录a数组中每个数的出现次数,sum记录cnt数组的出现次数
std::vector<int> v;
int n,size,t,m,now;
int cmp(query a,query b){return (pos[a.l]^pos[b.l])?pos[a.l]<pos[b.l]:((pos[a.l]&1)?a.r<b.r:a.r>b.r);}
inline void add(int x)
{
sum[cnt[aa[x]]]--;
sum[++cnt[aa[x]]]++;
if(cnt[aa[x]]>now) now=cnt[aa[x]];
}
inline void del(int x)
{
if(sum[cnt[aa[x]]]==1&&now==cnt[aa[x]]) now=cnt[aa[x]]-1;
sum[cnt[aa[x]]--]--;
sum[cnt[aa[x]]]++;
}
int main()
{
scanf("%d%d",&n,&m);
t=sqrt(n);
size=ceil((double)n/t);
for(int i=1;i<=size;i++)
for(int j=(i-1)*t+1;j<=i*t;j++)
pos[j]=i;//初始化
for(int i=1;i<=n;i++) scanf("%d",&aa[i]),v.emplace_back(aa[i]);//离散化
std::sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
for(int i=1;i<=n;i++) aa[i]=lower_bound(v.begin(),v.end(),aa[i])-v.begin()+1;
for(int i=1;i<=m;i++)
{
q[i].l=read(),q[i].r=read();
q[i].id=i;
}
sort(q+1,q+1+m,cmp);
int l=1,r=0;
for(int i=1;i<=m;i++)
{
int ql=q[i].l,qr=q[i].r;
while(l<ql) del(l++);
while(l>ql) add(--l);
while(r<qr) add(++r);
while(r>qr) del(r--);
ans[q[i].id]=-now;
}
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
return 0;
}