与众不同
题目链接:YbtOJ

解题思路
设
l
a
s
t
i
last_i
lasti 表示
i
i
i 上一次出现的位置。
设
p
r
e
i
pre_i
prei 表示以
i
i
i 结尾的最长完美序列的启示位置,显然
p
r
e
i
=
max
(
p
r
e
i
−
1
,
l
a
s
t
a
i
)
pre_i=\max(pre_{i-1},last_{a_i})
prei=max(prei−1,lastai) 。
我们先处理出
l
a
s
t
last
last 和
p
r
e
pre
pre ,然后二分出一个
l
e
n
len
len,
l
e
n
len
len 的左边可以直接求出答案,
l
e
n
len
len 的右边则可以用
s
t
st
st 表求出,取最大值即可。
code
#include<iostream>
#include<cstdio>
#include<cmath>
#define IN 1000001
using namespace std;
int n,m;
int a[200010];
int pre[200010];
int last[2000010];
int st[200010][20];
int fd(int x,int y)
{
int l=x,r=y,s=x;
while(l<=r)
{
int mid=(l+r)/2;
if(pre[mid]<x)
l=mid+1,s=mid;
else
r=mid-1;
}
return s;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
pre[1]=last[a[1]+IN]=st[1][0]=1;
for(int i=2;i<=n;i++)
{
pre[i]=max(pre[i-1],last[a[i]+IN]+1);
st[i][0]=i-pre[i]+1;
last[a[i]+IN]=i;
}
for(int j=1;j<=log2(n);j++)
for(int i=1;i+(1<<j)-1<=n;i++)
st[i][j]=max(st[i][j-1],st[i+(1<<j-1)][j-1]);
while(m--)
{
int x,y;
scanf("%d%d",&x,&y);
x++,y++;
int len=fd(x,y);
int ans=len-x+1;
int k=log2(y-len);
if(len<y)
ans=max(ans,max(st[len+1][k],st[y-(1<<k)+1][k]));
cout<<ans<<endl;
}
}
707



被折叠的 条评论
为什么被折叠?



