解决RMQ的st算法只占该问题的一小部分。
定义该子串为完美子串。
设 a[i] 为该序列,last[a[i]]为a[i]最后一次出现的位置。
首先预处理出以i下标结尾的的最长完美子串的首元素位置,存在st[i]。递推方程为st[i]=max(st[i-1],last[a[i]]+1)
然后得出每个以i下标结尾的最长完美子串的长度f[i][0]=i-st[i]+1。
在询问时,解由两种情况组成,在L~R中st[i]<L的和st[i]>=L的,用二分找出k使得st[k]>=L且st[k-1]<L
那么ans=max(k-L,query(k,R)) 其中query(k,R)为k~R中的最长完美子串长度(用RMQ方法解决)
特殊情况k>R时,ans=R-L+1;
例题loj10121
AC代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define lowbit(x) (x) & (-x)
const int maxn = 200000 + 10, maxk = 1000 + 10, MOD = 10056;
int n, m, k, pre[2000000 + 100], a[maxn], f[maxn][25], st[maxn], lg[maxn];
void RMQ() {
for (int i = 1; i <= n; i++) f[i][0] = i - st[i] + 1;
for (int j = 1; (1 << j) <= n; j++)
for (int i = 1; i + (1 << j) - 1 <= n; i++) f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}
int query(int L, int R) {
int k = lg[R - L + 1];
return max(f[L][k], f[R - (1 << k) + 1][k]);
}
int main() {
scanf("%d%d", &n, &m);
lg[0] = -1;
st[1] = 1;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
a[i] += 1000000;
if (i != 1)
st[i] = max(st[i - 1], pre[a[i]] + 1);
pre[a[i]] = i;
lg[i] = lg[i >> 1] + 1;
}
// for (int i=1;i<=n;i++) printf("%d ",st[i]);
// cout<<endl;
RMQ();
for (int i = 1; i <= m; i++) {
int L, R, ans = 0;
scanf("%d%d", &L, &R);
L++, R++;
int k = lower_bound(st + 1, st + 1 + n, L) - st; //返回st中第一个>=L的下标值
// printf("%d\n",k);
if (k > R)
ans = R - L + 1;
else
ans = max(k - L, query(k, R));
printf("%d\n", ans);
}
}