bzoj 2251

第一道后缀数组

后缀数组要维护三个数组:sa(suffix array), rk(rank)和ht(height)。

含义分别是:

sa[i]:将后缀按照字典序排序后,第i大的后缀的起始位置。

rk[i]:起始位置为i的后缀的排名。

ht[i]:起始位置为i的后缀与排名为rk[i]-1的后缀的最长公共前缀。

对于任意一个字串,一定是某个后缀的前缀。

然后从sa[1]开始,统计字串,每个后缀sa[i]的可能的字串的个数(不与前面统计的重复)是:n-sa[i]+1-ht[sa[i]]

然后就这羊枚举子串,幷向后暴力统计个数,这样还能保证字典序是从小到大。

 1 /**************************************************************
 2     Problem: 2251
 3     User: idy002
 4     Language: C++
 5     Result: Accepted
 6     Time:240 ms
 7     Memory:892 kb
 8 ****************************************************************/
 9
10 #include <cstdio>
11 #define maxn 3010
12
13 int n;
14 int aa[maxn];
15 int sa[2][maxn], rk[2][maxn], ht[maxn], vv[maxn], p;
16 char str[maxn];
17
18 void expand( int k, int sa[maxn], int rk[maxn], int tsa[maxn], int trk[maxn] ) {
19     for( int i=1; i<=n; i++ ) vv[rk[sa[i]]]=i;
20     for( int i=n; i>=1; i-- ) if( sa[i]>k ) tsa[vv[rk[sa[i]-k]]--]=sa[i]-k;
21     for( int i=n-k+1; i<=n; i++ ) tsa[vv[rk[i]]--]=i;
22     for( int i=1; i<=n; i++ ) trk[tsa[i]]=trk[tsa[i-1]]+(rk[tsa[i]]!=rk[tsa[i-1]]||rk[tsa[i]+k]!=rk[tsa[i-1]+k]);
23 }
24 void makeht() {
25     int k=0;
26     ht[sa[p][1]] = 0;
27     for( int i=1; i<=n; i++ ) {
28         if( rk[p][i]==1 ) continue;
29         int j=sa[p][rk[p][i]-1];
30         while( aa[i+k]==aa[j+k] ) k++;
31         ht[i] = k;
32         if( k>0 ) k--;
33     }
34 }
35 void suffix() {
36     p=0;
37     for( int i=1; i<=n; i++ ) vv[aa[i]]++;
38     for( int i=1; i<=2; i++ ) vv[i]+=vv[i-1];
39     for( int i=n; i>=1; i-- ) sa[p][vv[aa[i]]--]=i;
40     for( int i=1; i<=n; i++ ) rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(aa[sa[p][i]]!=aa[sa[p][i-1]]);
41     for( int k=1; k<n; k<<=1,p=1-p ) expand( k, sa[p], rk[p], sa[1-p], rk[1-p] );
42     makeht();
43 }
44
45 int main() {
46     scanf( "%d", &n );
47     scanf( "%s", str+1 );
48     for( int i=1; i<=n; i++ )
49         aa[i] = str[i]-‘0‘+1;
50     suffix();
51     for( int i=1; i<=n; i++ ) {
52         for( int t=sa[p][i]+ht[sa[p][i]]; t<=n; t++ ) {
53             int cnt=1;
54             for( int j=i+1; j<=n && ht[sa[p][j]]>=(t-sa[p][i]+1); j++,cnt++);
55             if( cnt>1 )
56                 printf( "%d\n", cnt );
57         }
58     }
59 }
60 

时间: 2024-08-06 10:16:04

bzoj 2251的相关文章

bzoj 2251: [2010Beijing Wc]外星联络 后缀数组

2251: [2010Beijing Wc]外星联络 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 424  Solved: 232[Submit][Status][Discuss] Description 小 P 在看过电影<超时空接触>(Contact)之后被深深的打动,决心致力于寻 找外星人的事业.于是,他每天晚上都爬在屋顶上试图用自己的收音机收听外星 人发来的信息.虽然他收听到的仅仅是一些噪声,但是他还是按照这些噪声的高 低电平将接收到

BZOJ 2251: [2010Beijing Wc]外星联络

2251: [2010Beijing Wc]外星联络 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 795  Solved: 477[Submit][Status][Discuss] Description 小 P 在看过电影<超时空接触>(Contact)之后被深深的打动,决心致力于寻找外星人的事业.于是,他每天晚上都爬在屋顶上试图用自己的收音机收听外星人发来的信息.虽然他收听到的仅仅是一些噪声,但是他还是按照这些噪声的高低电平将接收到的信号

外星联络(bzoj 2251)

Description 小 P 在看过电影<超时空接触>(Contact)之后被深深的打动,决心致力于寻找外星人的事业.于是,他每天晚上都爬在屋顶上试图用自己的收音机收听外星人发来的信息.虽然他收听到的仅仅是一些噪声,但是他还是按照这些噪声的高低电平将接收到的信号改写为由 0 和 1 构成的串, 并坚信外星人的信息就隐藏在其中.他认为,外星人发来的信息一定会在他接受到的 01 串中重复出现,所以他希望找到他接受到的 01 串中所有重复出现次数大于 1 的子串.但是他收到的信号串实在是太长了,于

BZOJ 2251 [2010Beijing Wc]外星联络 trie的性质以及字符串性质

题意:链接 方法: 字典树 解析: zxr讲过的题,当时听好像就有一个什么神奇的结论,然后今天做的时候想了半天想起来是什么结论了, 对于一个字符串,它的所有后缀的所有前缀就能代表该串的所有子串. 然后呢,我们可以将所有的后缀都加到trie树里.end记录以某点为结尾的串出现多少次. 然后trie树之所以为字典树就是其从右往左走恰好是字典序,所以递归跑一遍输出满足题意的解. 另外,数组版需要开到n^2的空间复杂度,别问我为什么,不然你会各种RE,OLE,总会有神奇的数据将你卡住,所以最好老老实实开

BZOJ 2251 2010Beijing WC 外星联络 后缀数组/Trie树

题目大意 给出一个字符串,问这个字符串中出现过1次以上的子串的个数,按照子串的字典序输出. 思路 由于数据范围过小,这个题有两个解法. 基本的想法就是用后缀数组来进行后缀的排序,之后按照height数组扫就可以了.应该是挺快的. 但是注意到数据范围只有3000,因此我们只需要弄出所有的后缀拿出来建立一颗后缀Trie树就行了.最后DFS一次树种的所有节点. CODE SuffixArray #include <cstdio> #include <cstring> #include &

bzoj 2251(后缀数组/后缀自动机)

题意: 给你一个长度为n的01串,问你这个串的所有子串中,出现次数大于1的子串的出现次数,最后按照字典序输出. 分析: 对于这个题目,我们显然可以用两种处理后缀的数据结构进行处理. 1:后缀自动机: 个人觉得在这个题中,用后缀自动机去解决会相对来说比较好理解. 我们知道,在后缀自动机上的结点状态\(st\),若前一个状态通过字符\(c\)与\(st\)相连,那么结点\(st\)表示的是\(endpos\)相同的子串的集合.而该点的\(endpos\)则代表的是以\(c\)为结尾的串的出现的位置集

BZOJ 1013: [JSOI2008]球形空间产生器sphere

二次联通门 : BZOJ 1013: [JSOI2008]球形空间产生器sphere /* BZOJ 1013: [JSOI2008]球形空间产生器sphere 高斯消元 QAQ SB的我也能终于能秒题了啊 设球心的坐标为(x,y,z...) 那么就可以列n+1个方程,化化式子高斯消元即可 */ #include <cstdio> #include <iostream> #include <cstring> #define rg register #define Max

bzoj 3309 DZY Loves Math - 莫比乌斯反演 - 线性筛

对于正整数n,定义f(n)为n所含质因子的最大幂指数.例如f(1960)=f(2^3 * 5^1 * 7^2)=3, f(10007)=1, f(1)=0. 给定正整数a,b,求sigma(sigma(f(gcd(i,j)))) (i=1..a, j=1..b). Input 第一行一个数T,表示询问数. 接下来T行,每行两个数a,b,表示一个询问. Output 对于每一个询问,输出一行一个非负整数作为回答. Sample Input 4 7558588 9653114 6514903 445

【BZOJ】[HNOI2009]有趣的数列

[算法]Catalan数 [题解] 学了卡特兰数就会啦>_<! 因为奇偶各自递增,所以确定了奇偶各自的数字后排列唯一. 那么就是给2n个数分奇偶了,是不是有点像入栈出栈序呢. 将做偶数标为-1,做奇数标为+1,显然当偶数多于奇数时不合法,因为它压不住后面的奇数. 然后其实这种题目,打表就可知啦--QAQ 然后问题就是求1/(n+1)*C(2n,n)%p了,p不一定是素数. 参考bzoj礼物的解法. 看到网上清一色的素数筛+分解质因数解法,不解了好久,感觉写了假的礼物-- 后来觉得礼物的做法才比