「一本通 4.2 例 3」与众不同 题解

感谢zyz大手子提供帮助%%%

solve

  • 先搞存储,发现有负数,-1e6~1e6,那么我们给每个数加上1e6,就行了(我之前用的二维数组记录正负+按位取反后++)
  • 我们看到是要求区间内不重复子串长,有一个显然的暴力做法
  • 那我们来考虑正解,我们随机搞一个不重复的子串,设为[x,y],设区间为[l,r],那么有四种情况:
    • 第一:x<l<r<y,答案为r-l+1
    • 第二:l<x<y<r,答案为y-x+1
    • 第三:l<x<r<y,答案为r-x+1
    • 第四:x<l<y<r,答案为y-l+1
  • 观察到,情况与子串的左端点相关,那么我们用last[]记录对于每个数,最长子串的起始位置
  • 我们要求最长,就要求在last中第一个大于l的值
  • 显然的二分查找,lower_bound
  • 对于找到的这个数,我们设成p
  • 对于p后的数,此时他们的最长子串的左端点大于l,那要找最长的,可以用RMQ求
  • 最后对结果取max
  • 代码细节多qwq

Code

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10,maxm=2e6+10;
int n,m;
int a[maxn];
int f[maxn][30];
int Log[maxn];
int last[maxm];
int v[maxm];
int query(int x,int y)
{
	int k=Log[y-x];
	return max(f[x][k],f[y-(1<<k)+1][k]);
}
void llog(){for (int i=2;i<=n;i++) Log[i]=Log[i>>1]+1;}
void ST()
{
	for (int j=1;j<=Log[n];j++)
	{
		for (int i=1;i<=n-(1<<j)+1;i++)
		{
			f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
		}
	}
}
int main()
{
	cin >> n >> m;
	for (int i=1;i<=n;i++)
	{
		cin >> a[i];
		a[i]+=1000000;// 处理负数
		last[i]=max(v[a[i]]+1,last[i-1]);
		v[a[i]]=i;
	}
	llog();
	for (int i=1;i<=n;i++) f[i][0]=i-last[i]+1;
	ST();
	while(m--)
	{
		int x,y;
		cin >> x >> y;
		x++;
		y++;
		int p=lower_bound(last+x,last+y+1,x+1)-last;
		if (p>y)
		{// 特判一下
			cout << y-x+1 << endl;
			continue;
		}
		int ans=p-x;
		int k=query(p+1,y);
		cout << max(ans,k) << endl;
	}
	return 0;
}
posted @ 2026-03-29 19:27  msjing  阅读(48)  评论(0)    收藏  举报