[JSOI2007]字符加密 后缀数组
题面:洛谷
题解:
我们考虑,如果可以将环上每个长度为len的串都提取出来,再做个排序,那这题我们就做出来了!
但是提取$n^2$,怎么办?
考虑破环成链,再扩充为原来的2倍。
然后直接做后缀排序,把长度大于len的串按排序结果顺次列下来,对于每个后缀取出前len个字符构成串,最后得到的就是我们要的排序结果。
为什么这样是对的?
假设我们的最终排序结果是S1, S2, S3, S4....Sn,我们在这些串后面乱加一些东西再排序并不会影响排序结果,因为字典序是要先比较前面的字符的,只有前面字符相同才会比较后面的字符。
所以如果乱加的东西对串的排名产生了影响,那只能说明被改变了相对排名的这几个串,是相同的。
这题就做完了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define R register int 4 #define AC 405000 5 6 int n, len, m = 127; 7 int sa[AC], rk[AC], p1[AC], p2[AC], b[AC], d[AC]; 8 char s[AC]; 9 10 void pre() 11 { 12 scanf("%s", s + 1), len = strlen(s + 1), n = len << 1; 13 for(R i = 1; i <= len; i ++) s[i + len] = s[i]; 14 for(R i = 1; i <= n; i ++) sa[i] = i, rk[i] = s[i]; 15 } 16 17 void ssort() 18 { 19 for(R i = 1; i <= n; i ++) ++ d[p2[i]]; 20 for(R i = 1; i <= m; i ++) d[i] += d[i - 1]; 21 for(R i = 1; i <= n; i ++) b[d[p2[i]] --] = i;//为i分配d[p2[i]]的排名 22 for(R i = 0; i <= m; i ++) d[i] = 0; 23 24 for(R i = 1; i <= n; i ++) ++ d[p1[i]]; 25 for(R i = 1; i <= m; i ++) d[i] += d[i - 1]; 26 for(R i = n; i; -- i) sa[d[p1[b[i]]] --] = b[i];//为b[i]分配d[p1[b[i]]]的排名(按序分配) 27 for(R i = 0; i <= m; i ++) d[i] = 0; 28 } 29 30 void sa_sort() 31 { 32 for(R k = 1; k <= n; k <<= 1) 33 { 34 for(R i = 1; i <= n; i ++) p1[i] = rk[i], p2[i] = rk[i + k]; 35 ssort(); 36 int tmp = 1; 37 rk[sa[1]] = 1; 38 for(R i = 2; i <= n; i ++) 39 rk[sa[i]] = (p1[sa[i - 1]] == p1[sa[i]] && p2[sa[i - 1]] == p2[sa[i]]) ? tmp : ++ tmp; 40 if(tmp >= n) break; 41 m = tmp; 42 } 43 } 44 45 void work() 46 { 47 for(R i = 1; i <= n; i ++) 48 { 49 if(sa[i] > len) continue; 50 printf("%c", s[sa[i] + len - 1]); 51 } 52 printf("\n"); 53 } 54 55 int main() 56 { 57 // freopen("in.in", "r", stdin); 58 pre(); 59 sa_sort(); 60 work(); 61 // fclose(stdin); 62 return 0; 63 }