题目大意:
就是现在对于给出的长度不超过90000的字符串进行Q(Q <= 500)次询问, 每次询问给出一个K, 要求输出第K小的子串(0 < K < 2^31)
其中相同的子串只算一次例如“aaa"的子串是"a", "aa", "aaa"
大致思路:
首先对于给出的字符串建立后缀自动机, 然后利用后缀自动机的性质, 所有相同的子串一定会在同一点终止, 那么, 从根开始, 每次都选择尽量小的字符走, 首先我们可以dfs预处理出每个状态点处代表的可能向下的不同字串有多少个, 然后就知道每个字符向下走会有多少种可能了, 于是根据这个图中每次沿着满足向下能找到第K小的边走即可
代码如下:
Result : Accepted Memory : 28672 KB Time : 410 ms
/* * Author: Gatevin * Created Time: 2015/4/10 9:54:27 * File Name: Rin_Tohsaka.cpp */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> using namespace std; const double eps(1e-8); typedef long long lint; #define foreach(e, x) for(__typeof(x.begin()) e = x.begin(); e != x.end(); ++e) #define SHOW_MEMORY(x) cout<<sizeof(x)/(1024*1024.)<<"MB"<<endl #define maxn 90010*2 #define maxm 90010 struct Suffix_Automation { struct State { State *par; State *go[26]; int val, mi, right; lint cnt; void init(int _val = 0) { par = 0, val = _val, mi = 0, cnt = 0, right = 0; memset(go, 0, sizeof(go)); } int calc() { if(par == 0) return 0; return val - par->val; } }; State *root, *last, *cur; State nodePool[maxn]; State* newState(int val = 0) { cur->init(val); return cur++; } void initSAM() { cur = nodePool; root = newState(); last = root; } void extend(int w) { State *p = last; State *np = newState(p->val + 1); np->right = 1; while(p && p->go[w] == 0) { p->go[w] = np; p = p->par; } if(p == 0) { np->par = root; } else { State *q = p->go[w]; if(p->val + 1 == q->val) { np->par = q; } else { State *nq = newState(p->val + 1); memcpy(nq->go, q->go, sizeof(q->go)); nq->par = q->par; q->par = nq; np->par = nq; while(p && p->go[w] == q) { p->go[w] = nq; p = p->par; } } } last = np; } int d[maxm]; State* b[maxn]; void topo() { int cnt = cur - nodePool; memset(d, 0, sizeof(d)); int maxVal = 0; for(int i = 1 ; i < cnt; i++) maxVal = max(maxVal, nodePool[i].val), d[nodePool[i].val]++; for(int i = 1; i <= maxVal; i++) d[i] += d[i - 1]; for(int i = 1; i < cnt; i++) b[d[nodePool[i].val]--] = &nodePool[i]; b[0] = root; } void SAMInfo() { State *p; int cnt = cur - nodePool; for(int i = cnt - 1; i > 0; i--) { p = b[i]; p->par->right += p->right; p->mi = p->par->val + 1; } } lint dfs(State *now)//返回从now状态向下有多少种可能的串 { if(now->cnt) return now->cnt; lint ret = 0; for(int i = 0; i < 26; i++) if(now->go[i]) ret += dfs(now->go[i]); return now->cnt = ret + (now != root); } void solve(lint K)//output the Kth smallest substring { State *now = root; while(K) { for(int i = 0; i < 26; i++) { if(!now->go[i]) continue; if(K > now->go[i]->cnt) K -= now->go[i]->cnt; else { putchar(i + 'a'); K--; now = now->go[i]; break; } } } putchar('\n'); return; } }; Suffix_Automation sam; char s[maxm]; int Q, K; int main() { scanf("%s", s); int len = strlen(s); sam.initSAM(); for(int i = 0; i < len; i++) sam.extend(s[i] - 'a'); sam.topo(); sam.SAMInfo(); sam.dfs(sam.root); scanf("%d", &Q); while(Q--) { scanf("%d", &K); sam.solve((lint)K); } return 0; }