您的位置:首页 > 其它

[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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  hash string