题解
题目大意 给你一个长度为n的序列 找出序列出现K次以上的最长后缀
使用后缀自动机将所有后缀排序 获得height数组 用set区间求最小值遍历一遍即可
AC代码
#include <stdio.h>
#include <iostream>
#include <set>
#include <algorithm>
using namespace std
;
typedef long long ll
;
const int INF
= 0x3f3f3f3f;
const int MAXN
= 1e6 + 10;
int a
[MAXN
];
int n
, r
;
int sa
[MAXN
];
int cnt
[MAXN
];
int rak
[MAXN
];
int tmp
[MAXN
];
int heig
[MAXN
];
void radix_sort(int *rk
, int *tp
)
{
for (int i
= 0; i
<= r
; i
++)
cnt
[i
] = 0;
for (int i
= 1; i
<= n
; i
++)
cnt
[rk
[tp
[i
]]]++;
for (int i
= 1; i
<= r
; i
++)
cnt
[i
] += cnt
[i
- 1];
for (int i
= n
; i
>= 1; i
--)
sa
[cnt
[rk
[tp
[i
]]]--] = tp
[i
];
}
void suffix(int *a
)
{
int *rk
= rak
, *tp
= tmp
;
for (int i
= 1; i
<= n
; i
++)
rk
[i
] = a
[i
- 1], tp
[i
] = i
;
r
= 1e6 + 5;
radix_sort(rk
, tp
);
for (int l
= 1, p
= 1, i
; p
< n
; l
<<= 1, r
= p
)
{
for (p
= 0, i
= n
- l
+ 1; i
<= n
; i
++)
tp
[++p
] = i
;
for (i
= 1; i
<= n
; i
++)
if (sa
[i
] > l
)
tp
[++p
] = sa
[i
] - l
;
radix_sort(rk
, tp
);
swap(rk
, tp
);
rk
[sa
[1]] = p
= 1;
for (i
= 2; i
<= n
; i
++)
{
if (tp
[sa
[i
]] != tp
[sa
[i
- 1]] || tp
[sa
[i
] + l
] != tp
[sa
[i
- 1] + l
])
p
++;
rk
[sa
[i
]] = p
;
}
}
}
void get_height()
{
for (int i
= 1; i
<= n
; i
++)
rak
[sa
[i
]] = i
;
int k
= 0;
for (int i
= 1; i
<= n
; i
++)
{
if (k
)
k
--;
int j
= sa
[rak
[i
] - 1];
while (a
[i
- 1 + k
] == a
[j
- 1 + k
])
k
++;
heig
[rak
[i
]] = k
;
}
}
int main()
{
#ifdef LOCAL
freopen("C:/input.txt", "r", stdin);
#endif
int K
;
cin
>> n
>> K
;
for (int i
= 0; i
< n
; i
++)
scanf("%d", &a
[i
]);
suffix(a
);
get_height();
multiset
<int> st
;
for (int i
= 2; i
< K
; i
++)
st
.insert(heig
[i
]);
int ans
= 0;
for (int i
= K
; i
<= n
; i
++)
{
if (i
- K
+ 1 >= 2)
st
.erase(st
.find(heig
[i
- K
+ 1]));
st
.insert(heig
[i
]);
ans
= max(ans
, *st
.begin());
}
cout
<< ans
<< endl
;
return 0;
}