BZOJ3172 后缀数组

题意:求出一篇文章中每个单词的出现次数

表示样例没看懂= =,为什么aaa的次数是1但aa的次数是3啊......

标准解法好像是AC自动机or后缀自动机,还有人用KMP暴力过的= =

用后缀数组做的。原来没刷过这种类型,顺便复习一下~

Reference:http://blog.sina.com.cn/s/blog_6e63f59e0101bpw5.html

以样例为例:

对于每个单词第一个字母对应的height,向上、向下数出height值大于等于单词长度的height的个数。

注意细节的处理= =

 1 //在BT5下attack的时候把数值调大点(超过2000)就行了,具体可以参见网上破解无线网密码的文章,就是抓包之后的那步,注入数据包的命令
 2 #include "iostream"
 3 #include "cstring"
 4 using namespace std;
 5 #define maxn 1010000
 6
 7 int wa[maxn],wb[maxn],wv[maxn],wws[maxn];
 8 int rank[maxn],height[maxn];
 9 int r[maxn],sa[maxn],ans[maxn],st[maxn],ln[maxn];
10 int n,len,tl;
11 char ts[maxn];
12
13 int cmp(int *r,int a,int b,int l)
14 {
15     return r[a]==r[b]&&r[a+l]==r[b+l];
16 }
17
18 void da(int *r,int *sa,int n,int m)
19 {
20     int i,j,p,*x=wa,*y=wb,*t;
21     for(i=0; i<m; i++) wws[i]=0;
22     for(i=0; i<n; i++) wws[x[i]=r[i]]++;
23     for(i=1; i<m; i++) wws[i]+=wws[i-1];
24     for(i=n-1; i>=0; i--) sa[--wws[x[i]]]=i;
25     for(j=1,p=1; p<n; j*=2,m=p)
26     {
27
28         for(p=0,i=n-j; i<n; i++) y[p++]=i;
29         for(i=0; i<n; i++) if(sa[i]>=j) y[p++]=sa[i]-j;
30         for(i=0; i<n; i++) wv[i]=x[y[i]];
31         for(i=0; i<m; i++) wws[i]=0;
32         for(i=0; i<n; i++) wws[wv[i]]++;
33         for(i=1; i<m; i++) wws[i]+=wws[i-1];
34         for(i=n-1; i>=0; i--) sa[--wws[wv[i]]]=y[i];
35         for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1; i<n; i++)
36             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
37     }
38     return;
39 }
40
41 void calheight(int *r,int *sa,int n)
42 {
43     int i,j,k=0;
44     for(i=1; i<=n; i++) rank[sa[i]]=i;
45     for(i=0; i<n; height[rank[i++]]=k)
46         for(k?k--:0,j=sa[rank[i]-1]; r[i+k]==r[j+k]; k++);
47     return;
48 }
49
50 int main()
51 {
52     ios::sync_with_stdio(false);
53     cin>>n;
54     len=0;
55     for (int i=1;i<=n;i++)
56     {
57         st[i]=len;
58         cin>>ts;
59         tl=strlen(ts);
60         ln[i]=tl;
61         for (int j=len;j<len+tl;j++)
62         {
63             char ch=ts[j-len];
64             int tn=ch;
65             r[j]=tn;
66         }
67         len+=tl;
68         r[len]=1;
69         len++;
70     }
71     r[len]=0;
72
73     da(r,sa,len+1,200);
74     calheight(r,sa,len);
75
76     //for (int i=0;i<=len+1;i++)
77     //    cout<<height[i]<<" ";
78     //cout<<endl;
79     for (int i=1;i<=n;i++)
80     {
81         int tmp=rank[st[i]];
82         int tl=tmp,tr=tmp+1,tlen=ln[i];
83         while ((height[tl]>=tlen)&&(tl>=0))      tl--;
84         while ((height[tr]>=tlen)&&(tr<=len))   tr++;
85         cout<<tr-tl<<endl;
86     }
87
88     return 0;
89 }
时间: 2024-11-06 16:15:15

BZOJ3172 后缀数组的相关文章

SPOJ 705 Distinct Substrings(后缀数组)

[题目链接] http://www.spoj.com/problems/SUBST1/ [题目大意] 给出一个串,求出不相同的子串的个数. [题解] 对原串做一遍后缀数组,按照后缀的名次进行遍历, 每个后缀对答案的贡献为n-sa[i]+1-h[i], 因为排名相邻的后缀一定是公共前缀最长的, 那么就可以有效地通过LCP去除重复计算的子串. [代码] #include <cstdio> #include <cstring> #include <algorithm> usi

hdu5769--Substring(后缀数组)

题意:求含有某个字母的某个字符串的不同子串的个数 题解:后缀数组,记录每个位置距离需要出现的字母的距离就可以了.因为不太了解后缀模版卡了一会,还是很简单的. 记住sa和height数组都是1-n的下标. //后缀数组 #include <stdio.h> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll;

hdu 3518 Boring counting 后缀数组LCP

题目链接 题意:给定长度为n(n <= 1000)的只含小写字母的字符串,问字符串子串不重叠出现最少两次的不同子串个数; input: aaaa ababcabb aaaaaa # output 2 3 3 思路:套用后缀数组求解出sa数组和height数组,之后枚举后缀的公共前缀长度i,由于不能重叠,所以计数的是相邻height不满足LCP >= i的. 写写对后缀数组倍增算法的理解: 1.如果要sa数组对应的值也是1~n就需要在最后加上一个最小的且不出现的字符'#',里面y[]是利用sa数

【tyvj1860】后缀数组

描述 我们定义一个字符串的后缀suffix(i)表示从s[i]到s[length(s)]这段子串.后缀数组(Suffix array)SA[i]中存放着一个排列,满足suffix(sa[i])<suffix(sa[i+1]) 按照字典序方式比较定义height[i]表示suffix(sa[i])与suffix(sa[i-1])之间的最长公共前缀长度,其中height[1]=0你的任务就是求出SA和height这两个数组.字符串长度<=200000 输入格式 一行,为描述中的字符串(仅会出现小写

BZOJ 3238 AHOI 2013 差异 后缀数组+单调栈

题目大意: 思路:一看各种后缀那就是后缀数组没跑了. 求出sa,height之后就可以乱搞了.对于height数组中的一个值,height[i]来说,这个值能够作为lcp值的作用域只在左边第一个比他小的位置到右边第一个比他小的位置.这个东西很明显可以倍增RMQ+二分/单调栈. 之后就是数学题了 Σlen[Ti] + len[Tj] = (len + 1) * len * (len - 1),之后吧所有求出来的Σ2 * lcp(Ti,Tj)减掉就是答案. 记得答案开long long CODE:

hdu 5030 Rabbit&#39;s String(后缀数组&amp;二分)

Rabbit's String Time Limit: 40000/20000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 288    Accepted Submission(s): 108 Problem Description Long long ago, there lived a lot of rabbits in the forest. One day, the

hdu 4416 Good Article Good sentence(后缀数组&amp;思维)

Good Article Good sentence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2308    Accepted Submission(s): 649 Problem Description In middle school, teachers used to encourage us to pick up pre

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

poj 3693 Maximum repetition substring(后缀数组)

题目链接:poj 3693 Maximum repetition substring 题目大意:求一个字符串中循环子串次数最多的子串. 解题思路:对字符串构建后缀数组,然后枚举循环长度,分区间确定.对于一个长度l,每次求出i和i+l的LCP,那么以i为起点,循环子串长度为l的子串的循环次数为LCP/l+1,然后再考虑一下从i-l+1~i之间有没有存在增长的可能性. #include <cstdio> #include <cstring> #include <vector>