题意:
求字典序第K大的子串
题解:
先求出后缀自动机对应节点
// 该节点后面所形成的自字符串的总数然后直接模拟即可
1 #include <set> 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include <string> 9 #include 10 #include 11 #include 12 #include 13 #include 14 15 #define pi acos(-1.0) 16 #define eps 1e-9 17 #define fi first 18 #define se second 19 #define rtl rt<<1 20 #define rtr rt<<1|1 21 #define bug printf("******\n") 22 #define mem(a, b) memset(a,b,sizeof(a)) 23 #define name2str(x) #x 24 #define fuck(x) cout<<#x" = "< 25 #define sfi(a) scanf("%d", &a) 26 #define sffi(a, b) scanf("%d %d", &a, &b) 27 #define sfffi(a, b, c) scanf("%d %d %d", &a, &b, &c) 28 #define sffffi(a, b, c, d) scanf("%d %d %d %d", &a, &b, &c, &d) 29 #define sfL(a) scanf("%lld", &a) 30 #define sffL(a, b) scanf("%lld %lld", &a, &b) 31 #define sfffL(a, b, c) scanf("%lld %lld %lld", &a, &b, &c) 32 #define sffffL(a, b, c, d) scanf("%lld %lld %lld %lld", &a, &b, &c, &d) 33 #define sfs(a) scanf("%s", a) 34 #define sffs(a, b) scanf("%s %s", a, b) 35 #define sfffs(a, b, c) scanf("%s %s %s", a, b, c) 36 #define sffffs(a, b, c, d) scanf("%s %s %s %s", a, b,c, d) 37 #define FIN freopen("../in.txt","r",stdin) 38 #define gcd(a, b) __gcd(a,b) 39 #define lowbit(x) x&-x 40 #define IO iOS::sync_with_stdio(false) 41 42 43 using namespace std; 44 typedef long long LL; 45 typedef unsigned long long ULL; 46 const ULL seed = 13331; 47 const LL INFLL = 0x3f3f3f3f3f3f3f3fLL; 48 const int maxm = 8e6 + 10; 49 const int INF = 0x3f3f3f3f; 50 const int mod = 1e9 + 7; 51 const int maxn = 250007; 52 53 struct Suffix_Automaton { 54 int last, tot, nxt[maxn << 1][26], fail[maxn << 1];//last是未加入此字符前最长的前缀(整个串)所属的节点的编号 55 int len[maxn << 1];// 最长子串的长度 (该节点子串数量 = len[x] - len[fa[x]]) 56 int sa[maxn << 1], c[maxn << 1]; 57 int sz[maxn << 1];// 被后缀链接的个数,方便求节点字符串的个数 58 LL num[maxn << 1];// 该状态子串的数量 59 LL maxx[maxn << 1];// 长度为x的子串出现次数最多的子串的数目 60 LL sum[maxn << 1];// 该节点后面所形成的自字符串的总数 61 LL subnum, sublen;// subnum表示不同字符串数目,sublen表示不同字符串总长度 62 int X[maxn << 1], Y[maxn << 1]; // Y表示排名为x的节点,X表示该长度前面还有多少个 63 void init() { 64 tot = last = 1; 65 fail[1] = len[1] = 0; 66 for (int i = 0; i < 26; i++) nxt[1][i] = 0; 67 } 68 69 void extend(int c) { 70 int u = ++tot, v = last; 71 len[u] = len[v] + 1; 72 num[u] = 1; 73 for (; v && !nxt[v][c]; v = fail[v]) nxt[v][c] = u; 74 if (!v) fail[u] = 1, sz[1]++; 75 else if (len[nxt[v][c]] == len[v] + 1) fail[u] = nxt[v][c], sz[nxt[v][c]]++; 76 else { 77 int now = ++tot, cur = nxt[v][c]; 78 len[now] = len[v] + 1; 79 memcpy(nxt[now], nxt[cur], sizeof(nxt[cur])); 80 fail[now] = fail[cur]; 81 fail[cur] = fail[u] = now; 82 for (; v && nxt[v][c] == cur; v = fail[v]) nxt[v][c] = now; 83 sz[now] += 2; 84 } 85 last = u; 86 //return len[last] - len[fail[last]];//多添加一个子串所产生不同子串的个数 87 } 88 89 void get_num() {// 每个节点子串出现的次数 90 for (int i = 1; i <= tot; i++) X[len[i]]++; 91 for (int i = 1; i <= tot; i++) X[i] += X[i - 1]; 92 for (int i = 1; i <= tot; i++) Y[X[len[i]]--] = i; 93 for (int i = tot; i >= 1; i--) num[fail[Y[i]]] += num[Y[i]]; 94 } 95 96 void get_maxx(int n) {// 长度为x的子串出现次数最多的子串的数目 97 get_num(); 98 for (int i = 1; i <= tot; i++) maxx[len[i]] = max(maxx[len[i]], num[i]); 99 } 100 101 void get_sum() {// 该节点后面所形成的自字符串的总数 102 get_num(); 103 for (int i = tot; i >= 1; i--) { 104 sum[Y[i]] = 1; 105 for (int j = 0; j <= 25; j++) 106 sum[Y[i]] += sum[nxt[Y[i]][j]]; 107 } 108 } 109 110 void get_subnum() {//本质不同的子串的个数 111 subnum = 0; 112 for (int i = 1; i <= tot; i++) subnum += len[i] - len[fail[i]]; 113 } 114 115 void get_sublen() {//本质不同的子串的总长度 116 sublen = 0; 117 for (int i = 1; i <= tot; i++) sublen += 1LL * (len[i] + len[fail[i]] + 1) * (len[i] - len[fail[i]]) / 2; 118 } 119 120 void get_sa() { //获取sa数组 121 for (int i = 1; i <= tot; i++) c[len[i]]++; 122 for (int i = 1; i <= tot; i++) c[i] += c[i - 1]; 123 for (int i = tot; i >= 1; i--) sa[c[len[i]]--] = i; 124 } 125 126 127 int minn[maxn << 1], mx[maxn << 1];//多个串的最长公共子串 128 //minn[i]表示多个串在后缀自动机i节点最长公共子串,mx[i]表示单个串的最长公共子串 129 130 void match(char s[]) { 131 mem(mx, 0); 132 int n = strlen(s), p = 1, maxlen = 0; 133 for (int i = 0; i < n; i++) { 134 int c = s[i] - 'a'; 135 if (nxt[p][c]) p = nxt[p][c], maxlen++; 136 else { 137 for (; p && !nxt[p][c]; p = fail[p]); 138 if (!p) p = 1, maxlen = 0; 139 else maxlen = len[p] + 1, p = nxt[p][c]; 140 } 141 mx[p] = max(mx[p], maxlen); 142 } 143 for (int i = tot; i; i--) 144 mx[fail[i]] = max(mx[fail[i]], min(len[fail[i]], mx[i])); 145 for (int i = tot; i; i--) 146 if (minn[i] == -1 || minn[i] > maxx[i]) minn[i] = mx[i]; 147 } 148 149 void get_kth(int k) {//求出字典序第K的子串 150 int pos = 1, cnt; 151 string s = ""; 152 while (k) { 153 for (int i = 0; i <= 25; i++) { 154 if (nxt[pos][i] && k) { 155 cnt = nxt[pos][i]; 156 if (sum[cnt] < k) k -= sum[cnt]; 157 else { 158 k--; 159 pos = cnt; 160 s += (char) (i + 'a'); 161 break; 162 } 163 } 164 } 165 } 166 cout << s << endl; 167 } 168 } sam; 169 170 char s[maxn]; 171 int Q; 172 173 int main() { 174 #ifndef ONLINE_JUDGE 175 FIN; 176 #endif 177 sam.init(); 178 sfs(s + 1); 179 int n = strlen(s + 1); 180 for (int i = 1; i <= n; i++) sam.extend((s[i] - 'a')); 181 sam.get_sum(); 182 sfi(Q); 183 while (Q--) { 184 int k; 185 sfi(k); 186 sam.get_kth(k); 187 } 188 #ifndef ONLINE_JUDGE 189 cout << "Totle Time : " << (double) clock() / CLOCKS_PER_SEC << "s" << endl; 190 #endif 191 return 0; 192 }