hdu 5442 Favorite Donut (最小表示法 or 后缀数组)
来源:互联网 发布:新手淘宝买什么摄影棚 编辑:程序博客网 时间:2024/06/07 20:12
题意:
给一个字符串,正向找一遍循环最小,逆向找一遍循环最小。
然后把两个最小根据下标关系,取一个答案。。
思路:
这道题用 后缀数组 很好解决。
但是,还有个更适合的方法,最小表示法算法。
最小表示法 - 周源 PPT
这是一个非常简洁的
int maxPresent(const char s[], int len) { int i = 0, j = 1, k = 0, t; while ( i < len && j < len && k < len ) { t = s[ (i + k) % len ] - s[ (j + k) % len ]; if ( !t ) ++ k; else { // 比较失败时,移动指针,k 置 0 // 求最小表示,移动大的一方 // 求最大表示, 移动小的一方 if ( t < 0 ) i += k + 1; else j += k + 1; if ( i == j ) ++ j; k = 0; } } return min(i, j);}
后缀数组 ver1
扩成2*n-1,正反两遍求sa,lcp,遍历sa
char s[N+5], rs[N+5];int main() { int t; scanf("%d", &t); while ( t -- ) { int n; scanf("%d%s", &n, s); reverse_copy(s, s + n, rs); string cw = s; cw += s; cw.erase(cw.end() - 1); string ccw = rs; ccw += rs; ccw.erase(ccw.end() - 1); int idx1 = -1, idx2 = -1; SA::construct_sa(cw, cw.length(), 1); for (int i = cw.length(); i >= 1; -- i) { if ( SA::sa[i] < n ) { int j = i; idx1 = SA::sa[i]; while ( j && SA::lcp[j-1] >= n ) { -- j; idx1 = min ( idx1, SA::sa[j] ); } break; } } SA::construct_sa(ccw, ccw.length(), 1); for (int i = ccw.length(); i >= 1; -- i) { if ( SA::sa[i] < n ) { int j = i; idx2 = SA::sa[i]; while ( j && SA::lcp[j-1] >= n ) { -- j; idx2 = max ( idx2, SA::sa[j] ); } break; } } string sub1 = cw.substr(idx1, n), sub2 = ccw.substr(idx2, n); int res = sub1.compare(sub2); idx2 = n - 1 - idx2; if ( res < 0 ) { printf("%d 1\n", idx2 + 1); } else if ( res > 0 ) { printf("%d 0\n", idx1 + 1); } else { if ( idx2 < idx1 ) { printf("%d 1\n", idx2 + 1); } else printf("%d 0\n", idx1 + 1); } } return 0;}
后缀数组 Ver2
用一个特殊字符把正反扩充后的串连起来,求一遍sa,和lcp。
然后扫一遍求答案。。
虽然简洁一些,但是慢许多
char s[N+5], rs[N+5];pair<int, int> trans(int idx, int n) { if ( idx > n ) { idx -= 2 * n; idx = n - 1 - idx; return make_pair( idx, 1 ); } else return make_pair( idx, 0 );}int main() { int t; scanf("%d", &t); while ( t -- ) { int n; scanf("%d%s", &n, s); reverse_copy(s, s + n, rs); string cw = s; cw += s; cw.erase(cw.end() - 1); string ccw = rs; ccw += rs; ccw.erase(ccw.end() - 1); string ss = cw + '$' + ccw; SA::construct_sa(ss, ss.length(), 1); pair<int, int> ans = make_pair(INT_MAX, INT_MAX); for (int i = ss.length(); i >= 1; -- i) { if ( SA::sa[i] < n || 2 * n <= SA::sa[i] && SA::sa[i] <= 3 * n - 1 ) { ans = trans( SA::sa[i], n ); int j = i; while ( j && SA::lcp[j-1] >= n ) { -- j; ans = min ( ans, trans( SA::sa[j], n ) ); } break; } } printf("%d %d\n", ans.first + 1, ans.second); } return 0;}
0 0
- hdu 5442 Favorite Donut (最小表示法 or 后缀数组)
- hdu 5442 F - Favorite Donut 后缀数组 / 字符串の最小表示法+kmp
- HDU 5442 Favorite Donut(后缀数组)
- HDU 5442 Favorite Donut (最大表示法+KMP || 后缀数组)
- hdu 5442 Favorite Donut(最小表示法+kmp)
- hdu 5442 Favorite Donut(kmp+最小表示法)
- hdu5442-字符串循环节&最小表示法|后缀数组(未补)|kmp+最小-Favorite Donut
- hdoj 5442 Favorite Donut 【KMP最大表示法 后缀数组】
- HDU 5442 Favorite Donut 最大最小表示法+KMP
- hdu 5442 Favorite Donut 最小表示法+KMP
- HDU 5442 Favorite Donut 后缀数组
- hdu 5442 Favorite Donut(后缀数组)
- HDU 5442 Favorite Donut(后缀数组)
- hdu 5442 Favorite Donut 后缀数组
- hdu 5442 Favorite Donut(后缀数组)
- HDU 5442Favorite Donut 后缀数组
- hdu 5442 Favorite Donut(最大表示法+kmp)
- HDU 5442 Favorite Donut(最大表示法)
- ubuntu 上查看内存信息
- Google性能工程师Ilya Grigorik谈HTTP/2
- lammps CUDA 编译
- 第三章HTML笔记
- 逆向教程->道具锁定篇②
- hdu 5442 Favorite Donut (最小表示法 or 后缀数组)
- [Android UI开发] Android 性能调优点
- MEAN 框架 解析 及安装步骤
- Android自定义RatingBar(评分控件)
- hdu1452因子和的积性函数
- css2选择器写法大全
- hdu5444-Elven Postman-最最朴素的二叉搜索树
- lintcode-两数之和-56
- sizeof(结构体)的值