【題解】【LOJ2102】「TJOI2015」弦論
阿新 • • 發佈:2020-07-20
題目連結
題目解法
字尾自動機入門題。
建立字尾自動機。求第 \(k\) 大可以考慮按位確定。把字尾自動機當成一個 trie 樹看,每次類似於平衡樹上查詢第 k 大的方式查詢即可。
總結
沒啥。
程式碼
#include <cstdio> #include <cstring> using namespace std; const int CN = 5e5 + 5, CNODE = 1e6 + 5; struct SAM { int edge[26], parent, len, size; bool leaf; } node[CNODE]; int last, ntot, N, T, K, topo[CNODE], buc[CN], num[2][CNODE]; int cnt = 0; void Extend(int c) { ++cnt; int p = last, newnode = ++ntot; node[newnode].len = node[last].len + 1; //先計算 newnode的 len,再將 last變成 newnode last = newnode; node[newnode].leaf = 1; for (; p && node[p].edge[c] == 0; p = node[p].parent) node[p].edge[c] = newnode; if (!p) node[newnode].parent = 1; else { int q = node[p].edge[c]; if (node[q].len == node[p].len + 1) node[newnode].parent = q; else { int clone = ++ntot; for (int i = 0; i < 26; ++i) node[clone].edge[i] = node[q].edge[i]; node[clone].leaf = 0; //clone的 endpos node[clone].parent = node[q].parent; node[clone].len = node[p].len + 1; node[q].parent = node[newnode].parent = clone; for (; p && node[p].edge[c] == q; p = node[p].parent) node[p].edge[c] = clone; } } } void GetSize() { for (int i = 1; i <= ntot; ++i) ++buc[node[i].len]; for (int i = 1; i <= N; ++i) buc[i] += buc[i - 1]; for (int i = ntot; i >= 1; --i) { topo[buc[node[i].len]--] = i; node[i].size = node[i].leaf; } for (int i = ntot; i >= 1; --i) { node[node[topo[i]].parent].size += node[topo[i]].size; if (topo[i] != 1) { num[0][topo[i]] = 1; num[1][topo[i]] = node[topo[i]].size; } for (int j = 0; j < 26; ++j) { if (node[topo[i]].edge[j]) { num[0][topo[i]] += num[0][node[topo[i]].edge[j]]; num[1][topo[i]] += num[1][node[topo[i]].edge[j]]; } } } } void Find() { int now = 1; node[1].size = 0; if (T == 0) for (int i = 2; i <= ntot; ++i) node[i].size = 1; num[T][1] = 0; while (K > node[now].size) { for (int i = 0; i < 26; ++i) { if (!node[now].edge[i]) continue; if (K <= num[T][node[now].edge[i]]) { K -= node[now].size; now = node[now].edge[i]; printf("%c", (char)i + 'a'); break; } else K -= num[T][node[now].edge[i]]; } } printf("\n"); } char str[CN]; int main() { scanf("%s%d%d", str + 1, &T, &K); N = strlen(str + 1); last = ntot = 1; for (int i = 1; i <= N; ++i) Extend(str[i] - 'a'); GetSize(); if (num[T][1] < K) printf("-1\n"); else Find(); fclose(stdin); fclose(stdout); return 0; }