SPOJ.com - Problem SUBLEX
这么裸的一个SAM,放在了死破OJ上面就是个坑。
注意用SAM做的时候输出要用一个数组存下来,然后再puts,不然一个一个字符输出会更慢。
还有一个就是不要多数据输入,估计最后多了几个没用的数字,反正我这么做一直无端端的RE。(就这样浪费了我一天好么!出数据的人这么不负责!)
最后就是,第k大的k是会超过子串数的。(这什么脑残配置?)
综上,这题除了坑就是坑。
代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N = 222222; 5 const int LAST = 90000; 6 const int K = 26; 7 8 struct Node { 9 Node *nx[K], *fail; 10 int dist; 11 long long sub; 12 13 void Clear(const int d = 0) { 14 memset(nx, 0, sizeof nx); 15 fail = 0; 16 dist = d; 17 sub = 0; 18 } 19 } ; 20 21 struct SAM { 22 Node node[N << 1]; 23 Node *root, *last; 24 int ttNode; 25 26 Node *Mem(const int d = 0) { 27 Node *temp = node + ttNode++; 28 29 temp->Clear(d); 30 31 return temp; 32 } 33 34 void Clear() { 35 ttNode = 0; 36 root = last = Mem(); 37 } 38 39 void Expand(const char c) { 40 const int idx = c - 'a'; 41 Node *p = last, *np = Mem(p->dist + 1); 42 43 for ( ; p && p->nx[idx] == 0; p = p->fail) { 44 p->nx[idx] = np; 45 } 46 if (p) { 47 Node *q = p->nx[idx]; 48 49 if (p->dist + 1 != q->dist) { 50 Node *nq = Mem(); 51 52 *nq = *q; 53 nq->dist = p->dist + 1; 54 q->fail = np->fail = nq; 55 for ( ; p && p->nx[idx] == q; p = p->fail) { 56 p->nx[idx] = nq; 57 } 58 } else { 59 np->fail = q; 60 } 61 } else { 62 np->fail = root; 63 } 64 last = np; 65 } 66 67 int dist[N << 1]; 68 Node *ptr[N << 1]; 69 70 void GetSub() { 71 memset(dist, 0, sizeof dist); 72 for (int i = 0; i < ttNode; ++i) { 73 ++dist[node[i].dist]; 74 } 75 for (int i = 1; i < ttNode; ++i) { 76 dist[i] += dist[i - 1]; 77 } 78 for (int i = 0; i < ttNode; ++i) { 79 ptr[--dist[node[i].dist]] = node + i; 80 } 81 for (int i = ttNode - 1; i >= 0; --i) { 82 Node *p = ptr[i]; 83 84 p->sub = 1; 85 for (int j = 0; j < K; ++j) { 86 if (p->nx[j]) { 87 p->sub += p->nx[j]->sub; 88 } 89 } 90 } 91 --node[0].sub; 92 //for (int i = 0; i < ttNode; ++i) { cout << node[i].dist << ' '; } cout << endl; 93 //for (int i = 0; i < ttNode; ++i) { cout << node[i].sub << ' '; } cout << endl; 94 //for (int i = 0; i < ttNode; ++i) { cout << i << ": "; for (int j = 0; j < K; ++j) { cout << (node[i].nx[j] ? node[i].nx[j] - node : -1) << ' '; } cout << endl; } 95 } 96 } sam; 97 98 char s[N], answer[N]; 99 100 void Generate(char *const s) { 101 srand(time(0)); 102 for (int i = 0; i < LAST; ++i) { 103 s[i] = rand() % 26 + 'a'; 104 } 105 s[LAST] = 0; 106 } 107 108 int Run() { 109 //while (~scanf("%s", s)) { 110 //while (1) { 111 //Generate(s); 112 scanf("%s", s); 113 sam.Clear(); 114 for (int i = 0; s[i]; ++i) { 115 sam.Expand(s[i]); 116 } 117 sam.GetSub(); 118 //cout << sam.root->sub << endl; 119 //if (sam.ttNode >= (N << 1)) { puts("???"); while (1) ; } 120 121 int n, k; 122 123 scanf("%d", &n); 124 while (n--) { 125 Node *p = sam.root; 126 int pos = 0; 127 128 scanf("%d", &k); 129 //if (k > sam.root->sub) { puts("..."); while (1) ; } 130 k = (k - 1) % sam.root->sub + 1; 131 while (k > 0) { 132 for (int i = 0; i < K; ++i) { 133 if (p->nx[i] == 0) { 134 continue; 135 } 136 137 const int cnt = p->nx[i]->sub; 138 139 if (cnt >= k) { 140 //putchar('a' + i); 141 answer[pos++] = 'a' + i; 142 p = p->nx[i]; 143 --k; 144 break; 145 } else { 146 k -= cnt; 147 } 148 } 149 } 150 answer[pos] = 0; 151 puts(answer); 152 //puts(""); 153 } 154 //} 155 156 return 0; 157 } 158 159 int main() { 160 //ios::sync_with_stdio(0); 161 return Run(); 162 }
UPD:还有更坑的,我开99999 * 2的SAM节点数是会TLE的,开222222 * 2才AC。我猜肯定是新增的数据各种问题,数据不在范围内了。
——written by LyonLys