「一本通 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;
}
$\mathscr{msjing}$

浙公网安备 33010602011771号