UVA 12206 - Stammering Aliens(后缀数组)

UVA 12206 - Stammering Aliens

题目链接

题意:给定一个序列,求出出现次数大于m,长度最长的子串的最大下标

思路:后缀数组,搞出height数组后,利用二分去查找即可

这题之前还写过hash的写法也能过,不过写后缀数组的时候,犯了一个傻逼错误,把none输出成node还一直找不到。。。这是刷题来第二次碰到这种逗比错误了,还是得注意。。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAXLEN = 40005;

struct Suffix {

    int s[MAXLEN];
    int sa[MAXLEN], t[MAXLEN], t2[MAXLEN], c[MAXLEN], n;
    int rank[MAXLEN], height[MAXLEN];

    void build_sa(int m) {
	n++;
	int i, *x = t, *y = t2;
	for (i = 0; i < m; i++) c[i] = 0;
	for (i = 0; i < n; i++) c[x[i] = s[i]]++;
	for (i = 1; i < m; i++) c[i] += c[i - 1];
	for (i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i;
	for (int k = 1; k <= n; k <<= 1) {
	    int p = 0;
	    for (i = n - k; i < n; i++) y[p++] = i;
	    for (i = 0; i < n; i++) if (sa[i] >= k) y[p++] = sa[i] - k;
	    for (i = 0; i < m; i++) c[i] = 0;
	    for (i = 0; i < n; i++) c[x[y[i]]]++;
	    for (i = 0; i < m; i++) c[i] += c[i - 1];
	    for (i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
	    swap(x, y);
	    p = 1; x[sa[0]] = 0;
	    for (i = 1; i < n; i++)
		x[sa[i]] = (y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k]) ? p - 1 : p++;
	    if (p >= n) break;
	    m = p;
	}
	n--;
    }

    void getHeight() {
	int i, j, k = 0;
	for (i = 1; i <= n; i++) rank[sa[i]] = i;
	for (i = 0; i < n; i++) {
	    if (k) k--;
	    int j = sa[rank[i] - 1];
	    while (s[i + k] == s[j + k]) k++;
	    height[rank[i]] = k;
	}
    }
} gao;

const int N = 40005;

int m;
char str[N];

int judge(int x) {
    int ans = -1;
    for (int i = 1; i <= gao.n; i++) {
	if (gao.n - gao.sa[i] < x) continue;
	int Max = gao.sa[i], cnt = 1;
	while (gao.height[i + 1] >= x && i < gao.n) {
	    Max = max(Max, gao.sa[i + 1]);
	    cnt++;
	    i++;
	}
	if (cnt >= m)
	    ans = max(ans, Max);
    }
    return ans;
}

void solve() {
    if (judge(1) == -1) {
	printf("none\n");
	return;
    }
    int l = 1, r = gao.n - m + 2;
    while (l < r) {
	int mid = (l + r) / 2;
	if (judge(mid) != -1) l = mid + 1;
	else r = mid;
    }
    l--;
    printf("%d %d\n", l, judge(l));
}

int main() {
    while (~scanf("%d", &m) && m) {
	scanf("%s", str);
	int len = strlen(str);
	for (int i = 0; i < len; i++)
	    gao.s[i] = str[i] - 'a' + 1;
	gao.s[len] = 0;
	gao.n = len;
	gao.build_sa(27);
	gao.getHeight();
	solve();
    }
    return 0;
}

UVA 12206 - Stammering Aliens(后缀数组),布布扣,bubuko.com

时间: 2024-12-25 14:39:54

UVA 12206 - Stammering Aliens(后缀数组)的相关文章

uva 12206 - Stammering Aliens(哈希)

题目链接:uva 12206 - Stammering Aliens 题目大意:给出一个字符串,找出至少出现m次的最长子串. 解题思路:哈希算法,将每个后缀数组建立一个哈希值,每次二分长度判断,每次判断时将哈希值排序,计数即可. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef unsigned long long ll; const int ma

POJ 3882 Stammering Aliens 后缀数组height应用

题目来源:POJ 3882 Stammering Aliens 题意:给你m一个一个字符串 求至少出现m次的最长字符串 可以在字符串中重叠出现 思路:二分长度l 然后从height数组中找长度大于等于l的前缀 #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 40010; char s[maxn]; int sa[maxn]; i

Uva 12206 Stammering Aliens

题目描述 输入输出格式 输入格式: 输出格式: 输入输出样例 输入样例#1: 3 baaaababababbababbab 11 baaaababababbababbab 3 cccccc 0 输出样例#1: 5 12 none 4 2 这个题后缀数组或者二分+hash好像都能做,,,但是我只是练一下后缀自动机而已hhhhh这个题我们求的显然就是right集合大小>=m的max{}的最大值,至于求最右开端的话,我们只需要记录一下right集合的最右点是哪个就行了,然后用这个减去答案长度就是最右开

UVA - 12206 Stammering Aliens (hash)

这题其实很容易想到2分长度,关键是2分后,怎么判断出现最多次的串是否>=m次了.这里需要用到hash来处理. 对于一个字符串   H[i] =H[i+1]*131+s[i]  ;其中 H[n]=0:那么对于一个长度为L的串 ,hanh[i,l]=H[i]-H[i+L]*x^L ; 这样记录每个字符串的hash值,然后再处理起来就比较简单了. VIEW CODE #include<cstdio> #include<algorithm> #include<iostream&

uva 10829 - L-Gap Substrings(后缀数组)

题目链接:uva 10829 - L-Gap Substrings 题目大意:给定一个字符串,问有多少字符串满足UVU的形式,要求U非空,V的长度为g. 解题思路:对字符串的正序和逆序构建后缀数组,然后枚举U的长度l,每次以长度l分区间,在l和l+d+g所在的两个区间上确定U的最大长度. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using nam

uva 10526 - Intellectual Property(后缀数组)

题目链接:uva 10526 - Intellectual Property 题目大意:给定两个文本,问说下面一个文本中在哪些位置上抄袭了上面个一个文本的,输出n个抄袭位置(不足n个情况全部输出),按照长度优先输出,长度相同的输出位置靠前的. 注意:空格,回车都算一个字符:一段字符只能是抄袭上面的一部分,比如上:NSB*SB 下:NSB 答案:NSB. 解题思路:将两个文本连接在一起,中间用没有出现的字符分割,然后处理处后缀数组,根据height数组的性质,求出哪些位置匹配的长度不为0(注意匹配

uva 12338 - Anti-Rhyme Pairs(后缀数组+RMQ)

题目链接:uva 12338 - Anti-Rhyme Pairs 题目大意:给定若干个字符串,每次询问两个字符串的最长公共前缀. 解题思路:本来应该将每个字符串连接起来做后缀数组,但其实可以直接把一个字符串看成是一个字符,然后排序了就对应是SA数组,然后处理height即可.然后根据后缀数组的性质,字符串i和j的最长公共前缀长度即为rank[i]+1~rank[j]之间height的最小值.特判i=j的情况. #include <cstdio> #include <cstring>

uva 11107 - Life Forms(后缀数组)

题目链接:uva 11107 - Life Forms 题目大意:给定n个字符串,求一个最长的字符串,为n/2个字符串的子串. 解题思路:后缀数组,处理除后缀数组后,二分长度,每次遍历height数组,当长度不足时就分段,如果存在一段中包含n/2个起点,则为可行长度. #include <cstdio> #include <cstring> #include <set> #include <algorithm> using namespace std; co

Uva 12361 File Retrieval 后缀数组+并查集

题意:有F个单词,1 <= F <=60 , 长度<=10^4, 每次可以输入一个字符串,所有包含该字串的单词会形成一个集合. 问最多能形成多少个不同的集合.集合不能为空. 分析:用后缀数组处理.然后首先考虑一个单词形成一个集合的情况,若该单词是其他单词的字串,则该单词显然不会形成一个集合,那么利用后缀数组, 对于每个单词看能否与其他单词有LCP,且LCP 长度为该单词本身长度. 然后就是多个单词形成集合的情况:比较简单的处理方式就是将h数组值相同的下标集中存储,比如h[x] = h[y