UVALive - 4513 Stammering Aliens ——(hash+二分 || 后缀数组加二分)

  题意:找一个出现了m次的最长子串,以及这时的最右的位置。

  hash的话代码还是比较好写的,,但是时间比SA多很多。。

 1 #include <stdio.h>
 2 #include <algorithm>
 3 #include <string.h>
 4 using namespace std;
 5 const int N = 40000 + 100;
 6 typedef long long ll;
 7 const int X = 257;
 8 const int mod = (int)1e9 + 7;
 9
10 char s[N];
11 int m,len,pw[N];
12 int H[N],pos;
13
14 struct node
15 {
16     int id,hash;
17     bool operator < (const node & temp) const
18     {
19         return hash == temp.hash ? id < temp.id : hash < temp.hash;
20     }
21 }p[N];
22
23 bool solve(int L)
24 {
25     int cnt = 0;
26     pos = -1;
27     for(int i=1;i+L-1<=len;i++)
28     {
29         int id = i;
30         int hash = ((ll)H[i] - (ll)H[i+L]*pw[L]) % mod;
31         if(hash < 0) hash += mod; // 注意这里!
32         p[i] = (node){id, hash};
33     }
34     sort(p+1, p+1+ len - L + 1);
35
36     for(int i=1;i<=len-L+1;i++)
37     {
38         if(i == 1 || p[i].hash != p[i-1].hash) cnt = 0;
39         if(++cnt >= m) pos = max(pos, p[i].id);
40     }
41     return pos != -1;
42 }
43
44 int main()
45 {
46     pw[0] = 1;
47     for(int i=1;i<N;i++) pw[i] = 1LL*pw[i-1] * X % mod;
48     while(scanf("%d",&m) == 1 && m)
49     {
50         scanf("%s",s+1);
51         len = strlen(s+1);
52         for(int i=len;i>=1;i--) H[i] = (1LL*H[i+1] * X + s[i] - ‘a‘) % mod;
53         int l = 1, r = len, ans = -1;
54         while(l <= r)
55         {
56             int mid = l + r >> 1;
57             if(solve(mid)) ans = mid, l = mid + 1;
58             else r = mid - 1;
59         }
60         solve(ans);
61         if(ans != -1) printf("%d %d\n",ans, pos-1);
62         else puts("none");
63     }
64     return 0;
65 }

hash的写法

  

  SA的话,写法需要细细体会一下了。。时间减少了很多。

 1 #include <stdio.h>
 2 #include <algorithm>
 3 #include <string.h>
 4 using namespace std;
 5 const int N = 40000 + 100;
 6 typedef long long ll;
 7 const int X = 257;
 8 const int mod = (int)1e9 + 7;
 9
10 char s[N];
11 int m,len,pw[N];
12 int H[N],pos;
13
14 struct node
15 {
16     int id,hash;
17     bool operator < (const node & temp) const
18     {
19         return hash == temp.hash ? id < temp.id : hash < temp.hash;
20     }
21 }p[N];
22
23 bool solve(int L)
24 {
25     int cnt = 0;
26     pos = -1;
27     for(int i=1;i+L-1<=len;i++)
28     {
29         int id = i;
30         int hash = ((ll)H[i] - (ll)H[i+L]*pw[L]) % mod;
31         if(hash < 0) hash += mod; // 注意这里!
32         p[i] = (node){id, hash};
33     }
34     sort(p+1, p+1+ len - L + 1);
35
36     for(int i=1;i<=len-L+1;i++)
37     {
38         if(i == 1 || p[i].hash != p[i-1].hash) cnt = 0;
39         if(++cnt >= m) pos = max(pos, p[i].id);
40     }
41     return pos != -1;
42 }
43
44 int main()
45 {
46     pw[0] = 1;
47     for(int i=1;i<N;i++) pw[i] = 1LL*pw[i-1] * X % mod;
48     while(scanf("%d",&m) == 1 && m)
49     {
50         scanf("%s",s+1);
51         len = strlen(s+1);
52         for(int i=len;i>=1;i--) H[i] = (1LL*H[i+1] * X + s[i] - ‘a‘) % mod;
53         int l = 1, r = len, ans = -1;
54         while(l <= r)
55         {
56             int mid = l + r >> 1;
57             if(solve(mid)) ans = mid, l = mid + 1;
58             else r = mid - 1;
59         }
60         solve(ans);
61         if(ans != -1) printf("%d %d\n",ans, pos-1);
62         else puts("none");
63     }
64     return 0;
65 }

SA的写法

  顺便想说一下的是,这里不知为何下标从1开始无限WA,以后用SA还是下标从0开始好了。。毕竟不懂SA的具体原理。

时间: 2024-10-06 19:31:51

UVALive - 4513 Stammering Aliens ——(hash+二分 || 后缀数组加二分)的相关文章

[bzoj1717][Usaco2006 Dec]Milk Patterns 产奶的模式 (hash构造后缀数组,二分答案)

以后似乎终于不用去学后缀数组的倍增搞法||DC3等blablaSXBK的方法了= = 定义(来自关于后缀数组的那篇国家集训队论文..) 后缀数组:后缀数组SA是一个一维数组,它保存1..n的某个排列SA[1],SA[2],……,SA[n],并且保证Suffix(SA[i])<Suffix(SA[i+1]),1≤i<n. 也就是将S的n个后缀从小到大进行排序之后把排好序的后缀的开头位置顺次放入SA中. height数组:定义height[i]=suffix(sa[i-1])和suffix(sa[

uvalive 4513 Stammering Aliens

题意:给你一个串,问期中至少出现m次的最长子串及其起始位置的坐标. 思路:hash+LCP+二分答案 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 const int maxn = 40000 + 10; 7 const int x = 123; 8 int n, m, pos; 9 unsigned long long H[maxn], x

LA 4513 Stammering Aliens 字符串hash

字符串hash模板, 本题是求,给定字符串s中至少出现m次的最长字符串长度,及此时起始位置的最大值 LA 4513  Stammering Aliens 白书p225 //#pragma warning (disable: 4786) //#pragma comment (linker, "/STACK:16777216") //HEAD #include <cstdio> #include <ctime> #include <cstdlib> #i

poj 2774 最长公共子串--字符串hash或者后缀数组或者后缀自动机

http://poj.org/problem?id=2774 想用后缀数组的看这里:http://blog.csdn.net/u011026968/article/details/22801015 本文主要讲下怎么hash去找 开始的时候写的是O(n^2 logn)算法 果断超时...虽然也用了二分的,, 代码如下: //hash+二分 #include <cstdio> #include <cstring> #include <algorithm> #include

poj 1743 最长不重叠重复子串 后缀数组+lcp+二分

题比较容易读懂,但是建模需动点脑子: 一个子串加常数形成的子串认为跟子串相同,求最长不重叠重复子串 题目中说 is disjoint from (i.e., non-overlapping with) at least one of its other appearance(s) 意味着不能重叠,举个例子 1, 2,3,  52, 53,54 1,2, 3和 52, 53,54满足题意,差值为51 枚举差值肯定不行------看了题解明白的:: 后项减去前一项得到: 1,1,1,49,1,1  

BZOJ 题目3172: [Tjoi2013]单词(AC自动机||AC自动机+fail树||后缀数组暴力||后缀数组+RMQ+二分等五种姿势水过)

3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 1890  Solved: 877 [Submit][Status][Discuss] Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. Input 第一个一个整数N,表示有多少个单词,接下来N行每行一个单词.每个单词由小写字母组成,N<=200,单词长度不超过10^6

poj 2774 最长公共子--弦hash或后缀数组或后缀自己主动机

http://poj.org/problem?id=2774 我想看看这里的后缀数组:http://blog.csdn.net/u011026968/article/details/22801015 本文主要讲下怎么hash去找 開始的时候写的是O(n^2 logn)算法 果断超时. ..尽管也用了二分的.. 代码例如以下: //hash+二分 #include <cstdio> #include <cstring> #include <algorithm> #incl

后缀数组LCP + 二分 - UVa 11107 Life Forms

Life Forms Problem's Link Mean: 给你n个串,让你找出出现次数大于n/2的最长公共子串.如果有多个,按字典序排列输出. analyse: 经典题. 直接二分判断答案. 判断答案p时,我们扫一遍height数组,如果height[i]<p时开辟一个新段. 判断时用set存储所在串编号,不仅起到去重的作用,而且也起到统计段长的作用. Time complexity: O(N*logN) Source code:  /** this code is made by cra

【BZOJ1717&amp;POJ3261】Milk Patterns(后缀数组,二分)

题意:求字符串的可重叠的k次最长重复子串 n<=20000 a[i]<=1000000 思路:后缀数组+二分答案x,根据height分组,每组之间的height>=x 因为可以重叠,所以只要判断是否有一组的height个数>=k即可 1 var sa,rank,x,y,a,wc,wd,height:array[0..1100000]of longint; 2 n,m,i,l,r,mid,last,k1:longint; 3 4 procedure swap(var x,y:long