[HDU 4080] Stammering Aliens (字符串哈希+二分)

原创 2016年08月30日 20:14:27

链接

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;
}
版权声明:想转就转吧,反正也是人人都会的东西:-(

相关文章推荐

HDU4080后缀数组

出现K次或K次以上最长子串,并且输出最右边的子串首字母坐标。 和之前总结的一个题一样,二分长度,找到统计height数组大于等于K的个数,满足返回true;这里因为还要找最右边子串首字母坐标,因而需...

ACM hash哈希字符串 模板 hdu4080

先二分长度,然后用hash来查询

HDU 4080 Stammering Aliens(后缀数组+二分)

Description 给出一个字符串,求这个字符串中重复次数不少于m次的最长字串长度以及这个子串在原串中最后一次出现的位置 Input 多组用例,每组用例第一行为一整数m,第二行为一长度不超过...
  • V5ZSQ
  • V5ZSQ
  • 2016年05月05日 22:23
  • 388

hdu 4080 Stammering Aliens 二分 hash

POJ 3882 TLE 需后缀数组 ------------ const int SEED = 13331; const int MAX_N = 50000 + 10; char s[MAX_N...
  • cyendra
  • cyendra
  • 2014年01月11日 21:26
  • 652

HDOJ 4080 Stammering Aliens

用hash挫字符串。。。。 Stammering Aliens Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 327...

OI 字符串 常用哈希方法

(同步个人博客 http://sxysxy.org/blogs/44 到csdn下面这个方法来自 算法竞赛入门经典-训练指南方法对于一个字符串s,令h[i] = h[i+1]*x + s[i] ,其中...

Codeforeces 727 E 字符串双Hash 2017/1/12

题目链接:见这里 题意:n个长度为k的字符串,首尾相接,按顺时针顺序写在一张CD上,每个字符串只写一次总字符串长度小于1e6。保证每个字符串不同。这样CD上就有了一个环形字符串,长度是n*k。又给出...

UVA 12338 哈希+二分最长前缀

每个字符串都哈希之后,二个之间二分出最长前缀! 需要注意的是不能用数组存,会暴,用vector就行了。 #pragma comment(linker, "/STACK:1024000000,102...

F 求最长公共字串 hash+二分

题目链接:http://acm.dlut.edu.cn/problem.php?id=1251 不知道这个链接其他人

【字符串哈希】 HDOJ 4080 Stammering Aliens

这道题用字符串哈希较慢。。。。C++超时。。。G++AC。。。 #include #include #include #include #include #includ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[HDU 4080] Stammering Aliens (字符串哈希+二分)
举报原因:
原因补充:

(最多只允许输入30个字)