[HDU 4080] Stammering Aliens (字符串哈希+二分)
2016-08-30 20:14
387 查看
链接
HDU 4080题意
每组数据为一个整数m和一个长度不小于m的字符串,求该字符串的一个子串,该子串在满足出现次数不小于m的同时应尽量长。输出该长度和最右侧出现的起始位置。如果存在多组数据,输出有最靠近右侧的那组。
思路
关于子串和长度的题目仿佛都可以用字符串哈希+二分来水一水。这题仍然是字符串哈希的题目,对这个字符串求哈希,然后二分长度,枚举对应长度的子串哈希。每个哈希值要存储在哈希表里并记录次数,由于定长子串的哈希是从左向右线性枚举的,因此很容易找到最右侧的解。
我使用了双重哈希,存储哈希表的方式不太好,是沿着环顺序存储的而不是链式存储,这样发生冲突每次都要顺次去找位置,很耗时。自然溢出的单重哈希也是可以过的,只要存得好。
代码
#include <cstdio> #include <iostream> #include <cstring> #include <set> #include <map> #include <vector> using namespace std; typedef unsigned long long ulint; typedef pair<ulint, ulint> Hash; #define maxn (40100) const ulint seed = 30007uLL; const ulint mod1 = 100007; const ulint mod2 = 1e9 + 1017uLL; ulint xp1[maxn], H1[maxn], xp2[maxn], H2[maxn]; int m, slen; char s[maxn]; ulint h1[mod1], h2[mod1]; int t[mod1], vis[mod1]; pair<int, int> check(int len) { memset(t, 0, sizeof(t)); memset(vis, 0, sizeof(vis)); int ans = -1; H1[0] = H2[0] = s[0] - 'a' + 1; for(int i = 1; i < len; i++) { H1[i] = (H1[i-1] * seed + s[i] - 'a' + 1) % mod1; //printf("H1[%d] = %llu\n", i, H1[i]); H2[i] = (H2[i-1] * seed + s[i] - 'a' + 1) % mod2; //printf("H2[%d] = %llu\n", i, H2[i]); } vis[H1[len-1]] = 1; h1[H1[len-1]] = H1[len-1]; h2[H1[len-1]] = H2[len-1]; t[H1[len-1]]++; if(t[H1[len-1]] >= m) ans = 0; for(int i = len; i < slen; i++) { H1[i] = ((H1[i-1] + mod1) - ((s[i-len] - 'a' + 1) * xp1[len-1]) % mod1) % mod1; H1[i] = (H1[i] * seed + s[i] - 'a' + 1) % mod1; H2[i] = ((H2[i-1] + mod2) - ((s[i-len] - 'a' + 1) * xp2[len-1]) % mod2) % mod2; H2[i] = (H2[i] * seed + s[i] - 'a' + 1) % mod2; int pos = H1[i]; while(vis[pos] && (h1[pos] != H1[i] || h2[pos] != H2[i])) { pos = (pos + 1) % mod1; } vis[pos] = 1; h1[pos] = H1[i]; h2[pos] = H2[i]; t[pos]++; if(t[pos] >= m) ans = i + 1 - len; } return make_pair(len, ans); } int main() { //freopen("4080.txt", "r", stdin); xp1[0] = xp2[0] = 1uLL; for(int i = 1; i < maxn; i++) { xp1[i] = (xp1[i-1] * seed) % mod1; xp2[i] = (xp2[i-1] * seed) % mod2; } while((cin >> m) && m) { scanf("%s", s); slen = strlen(s); int l = 1, r = slen, m; pair<int, int> ans = make_pair(0, -1); while(l <= r) { m = (l + r) >> 1; pair<int, int> ret = check(m); if(ret.second < 0) r = m - 1; else { ans = ret; l = m + 1; } } if(ans.second < 0) cout << "none" << endl; else cout << ans.first << " " << ans.second << endl; } return 0; }
4000
相关文章推荐
- HDU - 4495 (字符串哈希+二分+DP)
- 多校第二场——hdu4618——字符串hash,二分
- hdu 4080 Stammering Aliens 二分 hash
- HDU 3973 AC's String 字符串哈希
- HDU 4080 Stammering Aliens (后缀数组 + 二分答案)
- HDU 1496 Equations(哈希打表+二分暴力)
- hdu 3973 AC's String 字符串哈希处理 查询子串是否是模式串 可以修改
- HDU 5510 Bazinga(技巧 + 字符串哈希)
- 【二分答案】【字符串哈希】bzoj2084 [Poi2010]Antisymmetry
- hdu 5199 map或二分或哈希
- HDU 4821 String 字符串哈希
- hdu 2736 Surprising Strings(类似哈希,字符串处理)
- [后缀数组+二分] hdu 4080 Stammering Aliens
- BNUOJ 34490 Justice String,字符串哈希,二分
- HDU 1800 Flying to the Mars 字符串哈希||字典树||map
- hdu 4080 Stammering Aliens 二分 hash
- hdu 1496 二分或者哈希
- 【字符串哈希】 HDOJ 4080 Stammering Aliens
- hdu 1228 A + B 详细题解 字符串/哈希
- HDU 4821 String(字符串哈希)