字串資結
にゃー -by toshi
AC by Astrayt
SA by Thanksone
謝一說他要講SA
AC自動機
AC上來講
他能做啥
一次匹配一大堆字串
但他不會幫你刷AC
還記得Trie嗎?
還記得KMP嗎?
發動魔法卡
在Trie上建構Failure
小畫家時間
實作
struct ACA{
vector<vector<int>> trie;
vector<int> f;
void new_vertex(){trie.pb(vector<int> (26, 0)); f.pb(0);}
void init(){trie.clear(); f.clear(); new_vertex();}
void add_string(string s, int w){
int cur = 0;
for(char c:s){
if(trie[cur][c]) cur = trie[cur][c];
else {
new_vertex();
cur = trie[cur][c] = trie.size() - 1;
}
}
}
void fail(){
queue<int> bfs;
for(int i = 0; i < 26; ++i) if(trie[0][i]) bfs.pp(trie[0][i]);
while(bfs.size()){
int u = bfs.front(); bfs.pop();
for(int i = 0; i < 26; ++i){
skip(!trie[u][i])
int v = trie[u][i], bacc = f[u];
while(bacc && !trie[bacc][i]) bacc = f[bacc];
if(trie[bacc][i]) bacc = trie[bacc][i];
f[v] = bacc; bfs.pp(v);
}
}
}
}AC;
用在DP上
扣
#include <bits/stdc++.h>
using namespace std;
#define starburst ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
typedef long long ll;
#define int ll
#define vi vector<int>
#define pii pair<int,int>
#define pb push_back
#define pp push
#define ff first
#define ss second
void change(string &s){
for(char &c:s){
if(c == 'r') c = 0;
else if(c == 'g') c = 1;
else if(c == 'b') c = 2;
else c = 3;
}
}
struct AutoChicken{
vector<vector<int>> trie;
vector<int> val, f;
void new_vertex(){trie.pb(vector<int> (3, 0)); val.pb(0); f.pb(0);}
void init(){trie.clear(); val.clear(); f.clear(); new_vertex();}
void add_string(string s, int w){
int cur = 0;
for(char c:s){
if(trie[cur][c]) cur = trie[cur][c];
else {
new_vertex();
cur = trie[cur][c] = trie.size() - 1;
}
}
val[cur] += w;
}
void fail(){
queue<int> bfs;
for(int i = 0; i <= 2; ++i) if(trie[0][i]) bfs.pp(trie[0][i]);
while(bfs.size()){
int u = bfs.front(); bfs.pop();
for(int i = 0; i <= 2; ++i){
skip(!trie[u][i])
int v = trie[u][i], bacc = f[u];
while(bacc && !trie[bacc][i]) bacc = f[bacc];
if(trie[bacc][i]) bacc = trie[bacc][i];
f[v] = bacc;
val[v] += val[bacc];
bfs.pp(v);
}
}
}
}AC;
void solve(){
AC.init();
int n, k; cin >> n >> k;
for(int i = 1; i <= k; ++i){
string t; int w;
cin >> t >> w;
change(t); AC.add_string(t, w);
}
string s; cin >> s; change(s);
AC.fail();
vector<int> dp[2]; int S = AC.trie.size();
dp[0].assign(S, -1e18); dp[1].assign(S, -1e18); dp[0][0] = 0;
for(int i = 0; i < n; ++i){
dp[1].assign(S, -1e18);
for(int j = 0; j < S; ++j){
skip(dp[0][j] < 0)
for(int k = 0; k <= 2; ++k){
skip(s[i] != 3 && k != s[i])
int cur = j;
while(cur && !AC.trie[cur][k]) cur = AC.f[cur];
if(AC.trie[cur][k]) cur = AC.trie[cur][k];
dp[1][cur] = max(dp[1][cur], dp[0][j] + AC.val[cur]);
}
}
dp[0] = dp[1];
}
cout << *max_element(dp[0].begin(), dp[0].end());
}
signed main(){
starburst
int t = 1; //cin >> t;
while(t--) solve();
}
Reference
Suffix Array
簡稱 SA
把後綴排序
\(banana \implies \begin{bmatrix} a \\ ana \\ anana \\ banana \\ na \\ nana \end{bmatrix}\)
直接排序可能要花 \(O(N^2logN)\),很慢
所以我們砸倍增法
\(banana \implies \begin{bmatrix} 1 \ anana (1, 0) \\ 1 \ ana (1, 0) \\ 1 \ a (1, 0) \\ 2 \ banana (2, 0) \\ 3 \ nana (3, 0) \\ 3 \ na (3, 0) \end{bmatrix} \implies \begin{bmatrix} 1 \ a (1, 0) \\ 2 \ anana (1, 3) \\ 2 \ ana (1, 3) \\ 3 \ banana (2, 1) \\ 4 \ nana (3, 1) \\ 4 \ na (3, 1) \end{bmatrix} \\ \implies \begin{bmatrix} 1 \ a (1, 0) \\ 2 \ ana (2, 1) \\ 3 \ anana (2, 2) \\ 4 \ banana (3, 4) \\ 5 \ na (4, 0) \\ 6 \ nana (4, 4) \end{bmatrix} \implies \begin{bmatrix} 1 \ a (1, 0) \\ 2 \ ana (2, 0) \\ 3 \ anana (3, 1) \\ 4 \ banana (4, 5) \\ 5 \ na (5, 0) \\ 6 \ nana (6, 0) \end{bmatrix}\)
複雜度
倍增次數 \(O(logN) \times\) 排序時間 \(O(NlogN) \\ = O(Nlog^2N)\)
優化 : 可以用 radix sort,排序時間 \(O(N)\)
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
array<int, 100004> SA, RNK, L, R;
array<vector<int>, 100004> V;
void sort(array<int, 100004> &A, int n){
for(int i = 0; i < n; i++){
V[A[SA[i]]].pb(SA[i]);
}
for(int i = 0, k = 0; i < max(26, n); i++){
for(int v : V[i]) SA[k++] = v;
V[i].clear();
}
}
void SUF(string &S){
int n = S.size(), cnt = -1, l = -1, r = -1;
for(int i = 0; i < n; i++){
SA[i] = n - i - 1, RNK[i] = L[i] = S[i] - 'a';
}
sort(L, n);
for(int k = 1; k < n; k <<= 1, cnt = l = r = -1){
for(int i = 0; i < n; i++){
L[i] = RNK[i], R[i] = i + k < n? RNK[i + k] : 0;
}
sort(R, n), sort(L, n);
for(int i = 0; i < n; i++){
if(L[SA[i]] != l || R[SA[i]] != r) cnt++;
RNK[SA[i]] = cnt, l = L[SA[i]], r = R[SA[i]];
}
}
}
扣
SA 能作的東西
在 SA 上面二分搜
在 SA 上面砸資結 like 線段樹
在 SA 上面作最長共同前綴 (LCP)
LCP 建法
void CP(string &S){
int n = S.size();
for(int i = 0; i < n; i++) RNK[SA[i]] = i;
for(int i = 0, k, cp = 0; i < n; i++){
if(!RNK[i]) continue;
k = SA[RNK[i] - 1];
if(cp) cp--;
while(S[i + cp] == S[k + cp]) cp++;
LCP[RNK[i]] = cp;
}
}
題目
AC 作法
#include <bits/stdc++.h>
using namespace std;
#define starburst ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
typedef long long ll;
//#define int ll
#define vi vector<int>
#define pb push_back
#define pp push
#define pof pop_front
#define pob pop_back
#define skip(x) if(x)continue;
void turn(string &s){
for(char &c:s) c -= 'a';
}
struct AhoCorasick{
vector<vector<int>> trie;
vector<int> f, cnt, vec;
void new_vertex(){
trie.pb(vector<int> (26, 0));
f.pb(0); cnt.pb(0);
}
void init(){
trie.clear(), f.clear(), cnt.clear();
new_vertex(); vec = {0};
}
void add_string(string s, int &id){
int cur = 0;
for(char c:s){
if(trie[cur][c]) cur = trie[cur][c];
else {
new_vertex();
cur = trie[cur][c] = trie.size() - 1;
}
}
id = cur;
}
void fail(){
queue<int> bfs;
for(int i = 0; i < 26; ++i) if(trie[0][i]) bfs.pp(trie[0][i]);
while(bfs.size()){
int u = bfs.front(); bfs.pop(); vec.pb(u);
for(int i = 0; i < 26; ++i){
skip(!trie[u][i])
int v = trie[u][i], bacc = f[u];
while(bacc && !trie[bacc][i]) bacc = f[bacc];
if(trie[bacc][i]) bacc = trie[bacc][i];
f[v] = bacc; bfs.pp(v);
}
}
}
void DP(){
for(int i = vec.size() - 1; i >= 0; --i){
cnt[f[vec[i]]] += cnt[vec[i]];
}
}
};
void solve(){
AhoCorasick AC;
AC.init();
string s; cin >> s;
vector<int> id;
int n = s.size(), k, len = 0; cin >> k;
turn(s);
while(k--){
string t; cin >> t;
id.pb(0);
turn(t); AC.add_string(t, id[id.size() - 1]);
len += t.size();
if(len > 100000){
len = 0;
AC.fail();
for(int i = 0, cur = 0; i < n; ++i){
while(cur && !AC.trie[cur][s[i]]) cur = AC.f[cur];
if(AC.trie[cur][s[i]]) cur = AC.trie[cur][s[i]];
++AC.cnt[cur];
}
AC.DP();
for(int i:id) cout << AC.cnt[i] << '\n';
id.clear(), AC.init();
}
}
AC.fail();
for(int i = 0, cur = 0; i < n; ++i){
while(cur && !AC.trie[cur][s[i]]) cur = AC.f[cur];
if(AC.trie[cur][s[i]]) cur = AC.trie[cur][s[i]];
++AC.cnt[cur];
}
AC.DP();
for(int i:id) cout << AC.cnt[i] << '\n';
}
signed main(){
starburst
int t = 1; cin >> t;
while(t--) solve();
}
SA 作法
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
array<int, 10004> SA, RNK, L, R;
array<vector<int>, 10004> V;
void sort(array<int, 10004> &A, int n){
for(int i = 0; i < n; i++){
V[A[SA[i]]].pb(SA[i]);
}
for(int i = 0, k = 0; i < max(26, n); i++){
for(int v : V[i]) SA[k++] = v;
V[i].clear();
}
}
void SUF(string &S){
int n = S.size(), cnt = -1, l = -1, r = -1;
for(int i = 0; i < n; i++){
SA[i] = n - i - 1, RNK[i] = L[i] = S[i] - 'a';
}
sort(L, n);
for(int k = 1; k < n; k <<= 1, cnt = l = r = -1){
for(int i = 0; i < n; i++){
L[i] = RNK[i], R[i] = i + k < n? RNK[i + k] : 0;
}
sort(R, n), sort(L, n);
for(int i = 0; i < n; i++){
if(L[SA[i]] != l || R[SA[i]] != r) cnt++;
RNK[SA[i]] = cnt, l = L[SA[i]], r = R[SA[i]];
}
}
}
int cmp(string &S, string &T, int p, int t){
for(int i = 0; i < min((int)T.size(), (int)S.size() - p); i++){
if(T[i] != S[p + i]) return T[i] > S[p + i];
}
return T.size() + p > S.size()? 1 : t;
}
int BIS(string &S, string &T, int t){
int p = -1;
for(int i = 1 << 13; i; i >>= 1){
if(p + i < S.size() && cmp(S, T, SA[p + i], t)) p += i;
}
return p;
}
signed main(){
int t, q;
string T, P;
cin >> t;
while(t--){
cin >> T >> q;
SUF(T);
while(q--){
cin >> P;
cout << BIS(T, P, 1) - BIS(T, P, 0) << "\n";
}
}
return 0;
}
SA 作法
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
array<int, 100004> SA, RNK, L, R;
array<vector<int>, 100004> V;
void sort(array<int, 100004> &A, int n){
for(int i = 0; i < n; i++){
V[A[SA[i]]].pb(SA[i]);
}
for(int i = 0, k = 0; i < max(26, n); i++){
for(int v : V[i]) SA[k++] = v;
V[i].clear();
}
}
void SUF(string &S){
int n = S.size();
for(int i = 0; i < n; i++){
SA[i] = n - i - 1, RNK[i] = L[i] = S[i] - 'a';
}
sort(L, n);
for(int k = 1; k < n; k <<= 1){
for(int i = 0; i < n; i++){
L[i] = RNK[i], R[i] = i + k < n? RNK[i + k] : 0;
}
sort(R, n), sort(L, n);
for(int i = 0, cnt = -1, l = -1, r = -1; i < n; i++){
if(L[SA[i]] != l || R[SA[i]] != r) cnt++;
RNK[SA[i]] = cnt, l = L[SA[i]], r = R[SA[i]];
}
}
}
int cmp(string &S, string &T, int p, int t){
for(int i = 0; i < min(T.size(), S.size() - p); i++){
if(T[i] != S[p + i]) return T[i] > S[p + i];
}
return T.size() + p > S.size()? 1 : t;
}
int BIS(string &S, string &T, int t){
int p = -1;
for(int i = 1 << 16; i; i >>= 1){
if(p + i < S.size() && cmp(S, T, SA[p + i], t)) p += i;
}
return p;
}
signed main(){
string S, T;
int k;
cin >> S >> k;
SUF(S);
while(k--){
cin >> T;
cout << (BIS(S, T, 1) - BIS(S, T, 0)? "YES\n" : "NO\n");
}
return 0;
}
SA 作法
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
array<int, 100004> SA, RNK, L, R;
array<vector<int>, 100004> V;
void sort(array<int, 100004> &A, int n){
for(int i = 0; i < n; i++){
V[A[SA[i]]].pb(SA[i]);
}
for(int i = 0, k = 0; i < max(26, n); i++){
for(int v : V[i]) SA[k++] = v;
V[i].clear();
}
}
void SUF(string &S){
int n = S.size();
for(int i = 0; i < n; i++){
SA[i] = n - i - 1, RNK[i] = L[i] = S[i] - 'a';
}
sort(L, n);
for(int k = 1; k < n; k <<= 1){
for(int i = 0; i < n; i++){
L[i] = RNK[i], R[i] = i + k < n? RNK[i + k] : 0;
}
sort(R, n), sort(L, n);
for(int i = 0, cnt = -1, l = -1, r = -1; i < n; i++){
if(L[SA[i]] != l || R[SA[i]] != r) cnt++;
RNK[SA[i]] = cnt, l = L[SA[i]], r = R[SA[i]];
}
}
}
int cmp(string &S, string &T, int p, int t){
for(int i = 0; i < min(T.size(), S.size() - p); i++){
if(T[i] != S[p + i]) return T[i] > S[p + i];
}
return T.size() + p > S.size()? 1 : t;
}
int BIS(string &S, string &T, int t){
int p = -1;
for(int i = 1 << 16; i; i >>= 1){
if(p + i < S.size() && cmp(S, T, SA[p + i], t)) p += i;
}
return p;
}
signed main(){
string S, T;
int k;
cin >> S >> k;
SUF(S);
while(k--){
cin >> T;
cout << BIS(S, T, 1) - BIS(S, T, 0) << "\n";
}
return 0;
}
SA 作法
#include <bits/stdc++.h>
#define pb push_back
#define mid ((l + r) >> 1)
#define lc (p << 1)
#define rc ((p << 1) | 1)
using namespace std;
array<int, 100004> SA, RNK, L, R;
array<int, 400004> seg;
array<vector<int>, 100004> V;
void pull(int p){
seg[p] = min(seg[lc], seg[rc]);
}
void update(int p, int l, int r, int x, int v){
if(x < l || x > r) return;
if(l == r){
seg[p] = v;
return;
}
update(lc, l, mid, x, v);
update(rc, mid + 1, r, x, v);
pull(p);
}
int query(int p, int l, int r, int ql, int qr){
if(qr < l || ql > r) return 1 << 30;
if(ql <= l && qr >= r) return seg[p];
return min(query(lc, l, mid, ql, qr), query(rc, mid + 1, r, ql, qr));
}
void sort(array<int, 100004> &A, int n){
for(int i = 0; i < n; i++){
V[A[SA[i]]].pb(SA[i]);
}
for(int i = 0, k = 0; i < max(26, n); i++){
for(int v : V[i]) SA[k++] = v;
V[i].clear();
}
}
void SUF(string &S){
int n = S.size();
for(int i = 0; i < n; i++){
SA[i] = n - i - 1, RNK[i] = L[i] = S[i] - 'a';
}
sort(L, n);
for(int k = 1; k < n; k <<= 1){
for(int i = 0; i < n; i++){
L[i] = RNK[i], R[i] = i + k < n? RNK[i + k] : 0;
}
sort(R, n), sort(L, n);
for(int i = 0, cnt = -1, l = -1, r = -1; i < n; i++){
if(L[SA[i]] != l || R[SA[i]] != r) cnt++;
RNK[SA[i]] = cnt, l = L[SA[i]], r = R[SA[i]];
}
}
for(int i = 0; i < n; i++) update(1, 0, n, i, SA[i] + 1);
}
int cmp(string &S, string &T, int p, int t){
for(int i = 0; i < min(T.size(), S.size() - p); i++){
if(T[i] != S[p + i]) return T[i] > S[p + i];
}
return T.size() + p > S.size()? 1 : t;
}
int BIS(string &S, string &T, int t){
int p = -1;
for(int i = 1 << 16; i; i >>= 1){
if(p + i < S.size() && cmp(S, T, SA[p + i], t)) p += i;
}
return p;
}
signed main(){
string S, T;
int k, l, r;
cin >> S >> k;
SUF(S);
while(k--){
cin >> T;
l = BIS(S, T, 0), r = BIS(S, T, 1);
cout << (r - l? query(1, 0, S.size(), l + 1, r) : -1) << "\n";
}
return 0;
}
SA 作法
#include <bits/stdc++.h>
#define pb push_back
#define int long long
using namespace std;
array<int, 100004> SA, RNK, L, R, LCP;
array<vector<int>, 100004> V;
void sort(array<int, 100004> &A, int n){
for(int i = 0; i < n; i++){
V[A[SA[i]]].pb(SA[i]);
}
for(int i = 0, k = 0; i < max(26ll, n); i++){
for(int v : V[i]) SA[k++] = v;
V[i].clear();
}
}
void SUF(string &S){
int n = S.size(), cnt = -1, l = -1, r = -1;
for(int i = 0; i < n; i++){
SA[i] = n - i - 1, RNK[i] = L[i] = S[i] - 'a';
}
sort(L, n);
for(int k = 1; k < n; k <<= 1, cnt = l = r = -1){
for(int i = 0; i < n; i++){
L[i] = RNK[i], R[i] = i + k < n? RNK[i + k] : 0;
}
sort(R, n), sort(L, n);
for(int i = 0; i < n; i++){
if(L[SA[i]] != l || R[SA[i]] != r) cnt++;
RNK[SA[i]] = cnt, l = L[SA[i]], r = R[SA[i]];
}
}
}
int CP(string &S){
int n = S.size(), sum = 0;
for(int i = 0; i < n; i++) RNK[SA[i]] = i;
for(int i = 0, k, cp = 0; i < n; i++){
if(!RNK[i]) continue;
k = SA[RNK[i] - 1];
if(cp) cp--;
while(S[i + cp] == S[k + cp]) cp++;
LCP[RNK[i]] = cp;
sum += cp;
}
return sum;
}
signed main(){
int n;
string S;
cin >> S;
n = S.size(), SUF(S);
cout << n * (n + 1) / 2 - CP(S) << "\n";
return 0;
}
SA 作法
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
array<int, 100004> SA, RNK, L, R;
array<vector<int>, 100004> V;
void sort(array<int, 100004> &A, int n){
for(int i = 0; i < n; i++){
V[A[SA[i]]].pb(SA[i]);
}
for(int i = 0, k = 0; i < max(26, n); i++){
for(int v : V[i]) SA[k++] = v;
V[i].clear();
}
}
void SUF(string &S){
int n = S.size();
for(int i = 0; i < n; i++){
SA[i] = n - i - 1, RNK[i] = L[i] = S[i] - 'a';
}
sort(L, n);
for(int k = 1; k < n; k <<= 1){
for(int i = 0; i < n; i++){
L[i] = RNK[i], R[i] = i + k < n? RNK[i + k] : 0;
}
sort(R, n), sort(L, n);
for(int i = 0, cnt = -1, l = -1, r = -1; i < n; i++){
if(L[SA[i]] != l || R[SA[i]] != r) cnt++;
RNK[SA[i]] = cnt, l = L[SA[i]], r = R[SA[i]];
}
}
}
string CP(string &S){
int n = S.size(), lng = 0, p;
string ans;
for(int i = 0; i < n; i++) RNK[SA[i]] = i;
for(int i = 0, k, cp = 0; i < n; i++){
if(!RNK[i]) continue;
k = SA[RNK[i] - 1];
if(cp) cp--;
while(S[i + cp] == S[k + cp]) cp++;
if(lng < cp) lng = cp, p = i;
}
for(int i = 0; i < lng; i++) ans += S[p + i];
if(!lng) ans = "-1";
return ans;
}
signed main(){
string S, T;
cin >> S;
SUF(S);
cout << CP(S) << "\n";
return 0;
}
SA 作法
#include <bits/stdc++.h>
#define pb push_back
#define int long long
using namespace std;
array<int, 100004> SA, RNK, L, R, LCP;
array<vector<int>, 100004> V;
void sort(array<int, 100004> &A, int n){
for(int i = 0; i < n; i++){
V[A[SA[i]]].pb(SA[i]);
}
for(int i = 0, k = 0; i < max(26ll, n); i++){
for(int v : V[i]) SA[k++] = v;
V[i].clear();
}
}
void SUF(string &S){
int n = S.size(), cnt = -1, l = -1, r = -1;
for(int i = 0; i < n; i++){
SA[i] = n - i - 1, RNK[i] = L[i] = S[i] - 'a';
}
sort(L, n);
for(int k = 1; k < n; k <<= 1, cnt = l = r = -1){
for(int i = 0; i < n; i++){
L[i] = RNK[i], R[i] = i + k < n? RNK[i + k] : 0;
}
sort(R, n), sort(L, n);
for(int i = 0; i < n; i++){
if(L[SA[i]] != l || R[SA[i]] != r) cnt++;
RNK[SA[i]] = cnt, l = L[SA[i]], r = R[SA[i]];
}
}
}
void CP(string &S){
int n = S.size();
for(int i = 0; i < n; i++) RNK[SA[i]] = i;
for(int i = 0, k, cp = 0; i < n; i++){
if(!RNK[i]) continue;
k = SA[RNK[i] - 1];
if(cp) cp--;
while(S[i + cp] == S[k + cp]) cp++;
LCP[RNK[i]] = cp;
}
}
string CNT(string &S, int k){
int n = S.size(), p;
string ans;
for(p = 0; p < n; p++){
if(n - SA[p] - LCP[p] >= k) break;
k -= n - SA[p] - LCP[p];
}
for(int i = SA[p]; i < SA[p] + LCP[p] + k; i++) ans += S[i];
return ans;
}
signed main(){
int k;
string S, T;
cin >> S >> k;
SUF(S), CP(S);
cout << CNT(S, k) << "\n";
return 0;
}
SA 作法
#include <bits/stdc++.h>
#define int long long
#define pb push_back
#define mid ((l + r) >> 1)
#define lc (p << 1)
#define rc ((p << 1) + 1)
using namespace std;
array<int, 100004> SA, RNK, F, L;
array<int, 400004> seg, tag;
array<vector<int>, 100004> buk;
void pull(int p){
seg[p] = seg[lc] + seg[rc];
}
void push(int p, int l, int r){
seg[lc] += (mid - l + 1) * tag[p];
seg[rc] += (r - mid) * tag[p];
tag[lc] += tag[p];
tag[rc] += tag[p];
tag[p] = 0;
}
void update(int p, int ql, int qr, int v, int l, int r){
if(ql > r || qr < l) return;
if(ql <= l && qr >= r){
seg[p] += (r - l + 1) * v;
tag[p] += v;
return;
}
push(p, l, r);
update(lc, ql, qr, v, l, mid);
update(rc, ql, qr, v, mid + 1, r);
pull(p);
}
int query(int p, int ql, int qr, int l, int r){
if(ql > r || qr < l) return 0;
if(ql <= l && qr >= r) return seg[p];
push(p, l, r);
return query(lc, ql, qr, l, mid) + query(rc, ql, qr, mid + 1, r);
}
void sort(array<int, 100004> &A, int n){
int cnt = 0;
for(int i = 0; i < n; i++){
buk[A[SA[i]]].pb(SA[i]);
}
for(int i = 0; i < max(n, 26ll); i++){
for(int x : buk[i]) SA[cnt++] = x;
buk[i].clear();
}
}
void suf(string &S){
int n = S.size(), cnt, ff, ll;
for(int i = 0; i < n; i++){
SA[i] = n - i - 1;
RNK[i] = F[i] = S[i] - 'a';
}
sort(F, n);
for(int k = 1; k < n; k <<= 1){
cnt = ff = ll = -1;
for(int i = 0; i < n; i++){
F[i] = RNK[i];
L[i] = i + k < n? RNK[i + k] : 0;
}
sort(L, n);
sort(F, n);
for(int i = 0; i < n; i++){
if(F[SA[i]] == ff && L[SA[i]] == ll) RNK[SA[i]] = cnt;
else RNK[SA[i]] = ++cnt;
ff = F[SA[i]], ll = L[SA[i]];
}
}
for(int i = 0; i < n; i++){
update(1, i, i, n - SA[i], 0, n);
}
}
int bis(string &S, int t, int l, int r, char c){
int p = l - 1;
for(int i = 1 << 16; i > 0; i >>= 1){
if(p + i <= r && S[SA[p + i] + t] <= c) p += i;
}
return p;
}
char cha(string &S, int k, int t, int l, int r){
int p, n = S.size();
char cl = 'a', cr = 'z', cm;
while(cl != cr){
cm = (cl + cr) >> 1;
p = bis(S, t, l, r, cm);
if(query(1, l, p, 0, n) < k) cl = cm + 1;
else cr = cm;
}
return cl;
}
string see(string &S, int k){
int n = S.size(), l = 0, r = n - 1, t = 0, tmp;
char p;
string s;
while(k > 0){
p = cha(S, k, t, l, r);
tmp = l;
l = bis(S, t, l, r, p - 1) + 1;
k -= query(1, tmp, l - 1, 0, n);
r = bis(S, t, l, r, p);
update(1, l, r, -1, 0, n);
k -= r - l + 1;
s += p;
t++;
}
return s;
}
signed main(){
int k;
string S;
cin >> S >> k;
suf(S);
cout << see(S, k) << "\n";
return 0;
}
SA 作法
#include <bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
array<int, 100004> SA, RNK, F, L, sum;
array<vector<int>, 100004> buk;
void sort(array<int, 100004> &A, int n){
int cnt = 0;
for(int i = 0; i < n; i++){
buk[A[SA[i]]].pb(SA[i]);
}
for(int i = 0; i < max(n, 26ll); i++){
for(int x : buk[i]){
SA[cnt++] = x;
}
buk[i].clear();
}
}
void suf(string &S){
int n = S.size(), cnt, ff, ll;
for(int i = 0; i < n; i++){
SA[i] = n - i - 1;
RNK[i] = F[i] = S[i] - 'a';
}
sort(F, n);
for(int j = 1; j < n; j <<= 1){
cnt = ff = ll = -1;
for(int i = 0; i < n; i++){
F[i] = RNK[i];
L[i] = i + j < n? RNK[i + j] : 0;
}
sort(L, n);
sort(F, n);
for(int i = 0; i < n; i++){
if(F[SA[i]] == ff && L[SA[i]] == ll) RNK[SA[i]] = cnt;
else RNK[SA[i]] = ++cnt;
ff = F[SA[i]], ll = L[SA[i]];
}
}
}
void lcp(string &S){
int n = S.size(), cp = 0, k;
for(int i = 0; i < n; i++) RNK[SA[i]] = i;
for(int i = 0; i < n; i++){
if(!RNK[i]){
sum[0]++;
sum[n - i]--;
continue;
}
k = SA[RNK[i] - 1];
if(cp) cp--;
while(S[i + cp] == S[k + cp]) cp++;
sum[cp]++;
sum[n - i]--;
}
}
signed main(){
int ans = 0;
string S;
cin >> S;
suf(S);
lcp(S);
for(int i = 0; i < S.size(); i++){
ans += sum[i];
cout << ans << " ";
}
return 0;
}
AC & SA
By ck1090329王民人
AC & SA
- 214