【HackerRank】Functional Palindromes(回文树+后缀数组+lcp排序+字符串哈希+二分)
2016-08-29 18:59
357 查看
【HackerRank】Functional Palindromes(回文树+后缀数组+lcp排序+字符串哈希+二分)
这个页面抓不太好,大家点进去看吧~~
做过的用到数据结构+算法最多的一个题……真真是做ACM以来做的最最麻烦的一个题……
说白了其实就是板子大杂烩……但是会吐的那种。。
此外……此题价值75$……不要问我为什么。。。TOT
现在进入正片——
给你一个长n的字符串,仅由小写字母组成。然后q次询问。
每次询问该串的所有回文子串里,按字典序从小到大后第k个的回文串。输出它的f函数值。注意回文串不去重。
具体要做的就是,预处理母串的所有回文串,按字典序排序,然后快速找到第k个,输出对应f值。
分为如下子问题:
1·预处理母串所有回文子串——回文树,具体百度,然后与回文树恶战一场吧……!¥@#¥。然后可以把本质不同的回文子串以及对应的出现次数存起来,然后排序。存回文子串可以存该种回文子串出现的左右下标——用以排序。
2·把回文子串按字典序排序——预处理母串的后缀数组,然后可以搞RMQ,弄出来个快速lcp。这样对于上一步存起来的本质不同的回文子串左右下标,通过比较lcp,可以达到快速按字典序排序。
3·快速找到第k个——二分,预处理到某个串所需要的k的下界,这样可以快速二分出第k个串。
4·f函数——字符串哈希,一套板子生砸上……
然后就出来了……GG。。。
因为是边学边造轮子,所以代码比较丑陋……
代码如下:
这个页面抓不太好,大家点进去看吧~~
做过的用到数据结构+算法最多的一个题……真真是做ACM以来做的最最麻烦的一个题……
说白了其实就是板子大杂烩……但是会吐的那种。。
此外……此题价值75$……不要问我为什么。。。TOT
现在进入正片——
给你一个长n的字符串,仅由小写字母组成。然后q次询问。
每次询问该串的所有回文子串里,按字典序从小到大后第k个的回文串。输出它的f函数值。注意回文串不去重。
具体要做的就是,预处理母串的所有回文串,按字典序排序,然后快速找到第k个,输出对应f值。
分为如下子问题:
1·预处理母串所有回文子串——回文树,具体百度,然后与回文树恶战一场吧……!¥@#¥。然后可以把本质不同的回文子串以及对应的出现次数存起来,然后排序。存回文子串可以存该种回文子串出现的左右下标——用以排序。
2·把回文子串按字典序排序——预处理母串的后缀数组,然后可以搞RMQ,弄出来个快速lcp。这样对于上一步存起来的本质不同的回文子串左右下标,通过比较lcp,可以达到快速按字典序排序。
3·快速找到第k个——二分,预处理到某个串所需要的k的下界,这样可以快速二分出第k个串。
4·f函数——字符串哈希,一套板子生砸上……
然后就出来了……GG。。。
因为是边学边造轮子,所以代码比较丑陋……
代码如下:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <vector> #include <queue> #include <algorithm> #define LL long long #define Pr pair<int,int> using namespace std; const int INF = 0x3f3f3f3f; const int mod = 1e9+7; const int MAXN = 112345; int t1[MAXN],t2[MAXN],c[MAXN]; bool cp(int *r,int a,int b,int l) { return r[a] == r[b] && r[a+l] == r[b+l]; } void da(char *str,int *sa,int *rk,int *height,int n,int m) { n++; int i,j,p,*x = t1,*y = t2; for(i = 0; i < m; ++i) c[i] = 0; for(i = 0; i < n; ++i) c[x[i] = str[i]]++; for(i = 1; i < m; ++i) c[i] += c[i-1]; for(i = n-1; i >= 0; --i) sa[--c[x[i]]] = i; for(j = 1; j <= n; j <<= 1) { p = 0; for(i = n-j; i < n; ++i) y[p++] = i; for(i = 0; i < n; ++i) if(sa[i] >= j) y[p++] = sa[i]-j; for(i = 0; i < m; ++i) c[i] = 0; for(i = 0; i < n; ++i) c[x[y[i]]]++; for(i = 1; i < m; ++i) c[i] += c[i-1]; for(i = n-1; i >= 0; --i) sa[--c[x[y[i]]]] = y[i]; swap(x,y); p = 1; x[sa[0]] = 0; for(i = 1; i < n; ++i) x[sa[i]] = cp(y,sa[i-1],sa[i],j)? p-1: p++; if(p >= n) break; m = p; } int k = 0; n--; for(i = 0; i <= n; ++i) rk[sa[i]] = i; for(i = 0; i < n; ++i) { if(k) k--; j = sa[rk[i]-1]; while(str[i+k] == str[j+k]) k++; height[rk[i]] = k; } } int rk[MAXN],height[MAXN]; int RMQ[MAXN]; int mm[MAXN]; int best[20][MAXN]; void initRMQ(int n) { mm[0] = -1; for(int i = 1; i <= n; ++i) mm[i] = ((i&(i-1)) == 0)? mm[i-1]+1: mm[i-1]; for(int i = 1; i <= n; ++i) best[0][i] = i; for(int i = 1; i <= mm ; i++) for(int j = 1; j +(1<<i)-1 <= n; j++) { int a = best[i-1][j]; int b = best[i-1][j+(1<<(i-1))]; if(RMQ[a] < RMQ[b]) best[i][j] = a; else best[i][j] = b; } } int askRMQ(int a,int b) { int t; t = mm[b-a+1]; b -= (1<<t)-1; a = best[t][a]; b = best[t][b]; return RMQ[a] < RMQ[b]? a: b; } int lcp(int a,int b,int len) { if(a == b) return len-a; a = rk[a]; b = rk[b]; if(a > b) swap(a,b); return height[askRMQ(a+1,b)]; } struct node { int next[26]; int len; int sufflink; int num,l,r; }; char s[112345]; node tree[MAXN]; int num; // node 1 - root with len -1, node 2 - root with len 0 int suff; // max suffix palindrome bool addLetter(int pos) { int cur = suff, curlen = 0; int let = s[pos] - 'a'; while (true) { curlen = tree[cur].len; if (pos - 1 - curlen >= 0 && s[pos - 1 - curlen] == s[pos]) break; cur = tree[cur].sufflink; } if (tree[cur].next[let]) { suff = tree[cur].next[let]; tree[suff].num++; return false; } num++; suff = num; tree[num].len = tree[cur].len + 2; tree[num].r = pos; tree[num].l = pos-tree[num].len+1; tree[cur].next[let] = num; if (tree[num].len == 1) { tree[num].sufflink = 2; tree[num].num = 1; return true; } tree[num].num++; while (true) { cur = tree[cur].sufflink; curlen = tree[cur].len; if (pos - 1 - curlen >= 0 && s[pos - 1 - curlen] == s[pos]) { tree[num].sufflink = tree[cur].next[let]; break; } } return true; } void initTree() { num = 2; suff = 2; tree[1].len = -1; tree[1].sufflink = 1; tree[2].len = 0; tree[2].sufflink = 1; } int len; int r[MAXN]; int sa[MAXN]; vector <int> adj[MAXN]; vector <pair<Pr,int> > vc; void dfs(int u) { for(int i = 0; i < adj[u].size(); ++i) { dfs(adj[u][i]); tree[u].num += tree[adj[u][i]].num; } } bool cmp(pair<Pr,int> a,pair<Pr,int> b) { int l1,l2,r1,r2,len1,len2; l1 = a.first.first; l2 = b.first.first; r1 = a.first.second; r2 = b.first.second; len1 = r1-l1+1; len2 = r2-l2+1; int cp = lcp(l1,l2,len); if(cp >= len1 || cp >= len2) return len1 <= len2; else return s[l1+cp] <= s[l2+cp]; } int P[MAXN],HashF[MAXN],HashR[MAXN]; class RollingHash { public: RollingHash() { prime = 100001; mod1 = 1000000007; mod2 = 1897266401; P[0] = 1; for(int i=1; i<MAXN; i++) { P[i] = 1LL * P[i-1] * prime % mod1; } } void Construct() { HashF[0] = HashR[ len+1 ] = 0; for(int i=1; i<=len; i++) { HashF[i] = ( 1LL * HashF[i-1] * prime + s[i-1] ) % mod1; HashR[len-i+1] = ( 1LL * HashR[len-i+2] * prime + s[ len - i ] ) % mod1; } } int GetForwardHash( int l, int r ) { if( l == 1 ) return HashF[r]; int hash = HashF[r] - 1LL * HashF[l-1] * P[ r - l + 1 ] % mod1; if( hash < 0 ) hash += mod1; return hash; } int GetBackwardHash( int l, int r ) { if( r == len ) return HashR[l]; int hash = HashR[l] - 1LL * HashR[r+1] * P[ r - l + 1 ] % mod1; if( hash < 0 ) hash += mod1; return hash; } bool IsPalin( int l, int r ) { if( r < l ) return true; return (GetForwardHash(l, r) == GetBackwardHash(l, r)); } private: int prime, mod1, mod2; }; vector <pair<LL,int> > by; LL ans[MAXN]; LL cnt; void init() { da(s,sa,rk,height,len,128); for(int i = 1; i <= len; ++i) RMQ[i] = height[i]; initRMQ(len); initTree(); for (int i = 0; i < len; i++) addLetter(i); for(int i = 2; i <= num; ++i) adj[tree[i].sufflink].push_back(i); dfs(1); for(int i = 3; i <= num; ++i) vc.push_back(pair<Pr,int> (Pr(tree[i].l,tree[i].r),tree[i].num)); sort(vc.begin(),vc.end(),cmp); RollingHash obj; obj.Construct(); cnt = 1; for(int i = 0; i < vc.size(); ++i) { by.push_back(pair<LL,int> (cnt,i)); ans[i] = obj.GetForwardHash(vc[i].first.first+1,vc[i].first.second+1); //printf("%d %d %lld\n",vc[i].first.first+1,vc[i].first.second+1,ans[i]); cnt += vc[i].second; } } int main() { int q; LL k; scanf("%d%d",&len,&q); scanf("%s",s); init(); int pos; while(q--) { scanf("%lld",&k); if(k >= cnt) puts("-1"); else { pos = -1; int l = 0,r = by.size()-1; while(l <= r) { int mid = (l+r)>>1; if(k >= by[mid].first) { pos = mid; l = mid+1; } else r = mid-1; } printf("%lld\n",ans[by[pos].second]); } } return 0; }
相关文章推荐
- [Hackerrank题目选做] Random Number Generator 二分+数学+猜结论
- [Hackerrank题目选做] Sorted Subsegments 二分+线段树
- hackerrank DAG Queries 定期重构+bitset
- HackerRank# Candies
- HackerRank# Bricks Game
- HackerRank - "String Modification"
- HackerRank - "Two arrays"
- HackerRank - "Team Formation"
- HackerRank难题记录
- HackerRank Medium(30) Maximal AND Subsequences 贪心+计数
- HackerRank "Simplified Chess Engine I & II"
- Codeforces 166A Rank List(二分)
- C++ HackerRank|AND xor OR
- HackerRank Extra long factorials
- 【hackerrank】World CodeSprint 11 T4
- HackerRank - powers-game-1 【博弈论】
- hackerrank>Dashboard>C++>STL>Lower Bound-STL
- HackerRank - beautiful-binary-string 【字符串】
- hackerrank 训练军队
- 【HackerRank】Maximizing XOR