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

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

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

ACM hash哈希字符串 模板 hdu4080

先二分长度,然后用hash来查询
  • nickwong_
  • nickwong_
  • 2014年08月23日 18:19
  • 1937

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

链接HDU 4080题意每组数据为一个整数m和一个长度不小于m的字符串,求该字符串的一个子串,该子串在满足出现次数不小于m的同时应尽量长。 输出该长度和最右侧出现的起始位置。如果存在多组数据,输出有...
  • zichenzhiguang
  • zichenzhiguang
  • 2016年08月30日 20:14
  • 469

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
  • 689

[后缀数组+二分] hdu 4080 Stammering Aliens

题意:最长重复出现至少k次的子串且输出最靠右的子串起始位置的下标。 注意2 ababcece 输出的是2 6...
  • wdcjdtc
  • wdcjdtc
  • 2014年08月29日 17:17
  • 455

HDU 4080 Stammering Aliens

刚开始直接把一个全局变量直接在函数里面赋值,结果一直WA 后来学乖了,里面用函数返回值把值传出来,就AC了 以后还是尽量少用全局变量吧,尤其是在有循环的地方,往往容易出错 还摸索出一个对付WA的...
  • lj94093
  • lj94093
  • 2015年04月01日 13:45
  • 461

LA-4513 - Stammering Aliens-(hash字符串+二分答案+hash排序) 找出子串出现次数

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&categ...
  • viphong
  • viphong
  • 2015年10月05日 18:09
  • 481

bzoj 1692 二分+hash

如果当前两边字符不同,那么选小的那边。否则二分+hash找到第一个不同的位置,如果左边小输左边,否则输右边。 逗比输出。。。#include using namespace std; #defin...
  • make_it_for_good
  • make_it_for_good
  • 2016年10月18日 18:36
  • 226

Poj 2774 二分+字符串hash

题意:给两个长1e5的字符串,求最长公共子串长度 做法:二分答案+hash。hash的思路大概是把字符串看做是p进制数,为了尽可能避免冲突,p取素数31或131等。hash完了排序,通过判断hash...
  • MrBird_to_fly
  • MrBird_to_fly
  • 2016年10月27日 15:16
  • 212

字符串hash + 二分答案 - 求最长公共子串 --- poj 2774

Long Long Message Problem's Link:http://poj.org/problem?id=2774   Mean:   求两个字符串的最长公共子串的长度。 a...
  • u013371163
  • u013371163
  • 2017年03月05日 17:13
  • 177
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[HDU 4080] Stammering Aliens (字符串哈希+二分)
举报原因:
原因补充:

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