[ACDream 1430]SETI 后缀数组

题目链接:http://acdream.info/problem?pid=1430

题目大意:给你一个长度不超过10000的字符串,问你出现过两次或两次以上的不重叠的子串有多少个。

后缀数组计算出height数组出来,然后分组。

如果没有分在一组的话代表两个的前缀是不相同的。于是就可以暴力搞了。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4
 5 using namespace std;
 6 typedef long long LL;
 7
 8 const int maxn = 1e5+100;
 9 int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
10 int sa[maxn],r[maxn];
11 int rank[maxn],height[maxn];
12 char s[maxn];
13 int cmp(int *r,int a,int b,int l){
14     return r[a]==r[b]&&r[a+l]==r[b+l];
15 }
16
17 void da(int *r,int *sa,int n,int m){
18     int i,j,p,*x=wa,*y=wb,*t;
19     for(i=0;i<m;i++) ws[i] = 0;
20     for(i=0;i<n;i++) ws[x[i]=r[i]]++;
21     for(i=1;i<m;i++) ws[i]+= ws[i-1];
22     for(i=n-1;i>=0;i--) sa[--ws[x[i]]] = i;
23     for(j=1,p=1;p<n;j*=2,m=p){
24         for(p=0,i=n-j;i<n;i++) y[p++] = i;
25         for(i=0;i<n;i++) if(sa[i]>=j) y[p++] = sa[i]-j;
26         for(i=0;i<n;i++) wv[i] = x[y[i]];
27         for(i=0;i<m;i++) ws[i] = 0;
28         for(i=0;i<n;i++) ws[wv[i]]++;
29         for(i=1;i<m;i++) ws[i]+=ws[i-1];
30         for(i=n-1;i>=0;i--) sa[--ws[wv[i]]] = y[i];
31         for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
32             x[sa[i]] = cmp(y,sa[i-1],sa[i],j)?p-1:p++;
33     }
34 }
35
36 void calheight(int *r,int *sa,int n){
37     int i,j,k=0;
38     for(i=1;i<=n;i++) rank[sa[i]]=i;
39     for(i=0;i<n;height[rank[i++]]=k)
40         for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
41 }
42
43 int main(){
44     gets(s);
45     int len = strlen(s);
46     for(int i=0;i<len;i++){
47         r[i] = s[i] - ‘a‘ + 1;
48     }
49     da(r,sa,len+1,100);
50     calheight(r,sa,len);
51 //    for(int i=1;i<=len;i++){
52 //        printf("%d ",sa[i]);
53 //    }
54 //    puts("");
55 //    for(int i=2;i<=len;i++) printf("%d ",height[i]); puts("");
56     int ans = 0;
57     for(int k=1;k<=len;k++){
58         int maxn = sa[1] , minn = sa[1];
59         int q = 0;
60 //        printf("now k=%d\n",k);
61         for(int i=2;i<=len+1;i++){
62             if( height[i]<k||i==len+1 ){
63                 if( maxn-minn>=k ) ans++;
64                 maxn = minn = sa[i];
65 //                printf("i=%d sa[i]=%d maxn = %d minn = %d\n",i,sa[i],maxn,minn);
66             } else if(i<=len){
67                 maxn = max(sa[i],maxn);
68                 minn = min(sa[i],minn);
69             }
70         }
71 //        printf("k=%d q=%d\n",k,q);
72 //        q = 0;
73     }
74     printf("%d\n",ans);
75     return 0;
76 }

时间: 2024-10-07 08:49:24

[ACDream 1430]SETI 后缀数组的相关文章

acdream 1430 SETI 后缀数组+height分组

这题昨天比赛的时候逗了,后缀想不出来,因为n^2的T了,就没往后缀数组想--而且之后解题的人又说用二分套二分来做,然后就更不会了-- 刚才看了题解,唉--原来题解说n^2的也可以过,然后就--这样了! #pragma comment(linker, "/STACK:1024000000,1024000000") #include<iostream> #include<cstdio> #include<cstring> #include<algo

HDU 5008西安网络赛B题:后缀数组求第k小子串

思路:尼玛,这题搞了一天了,比赛的时候用了n^2的方法绝对T了,然后今天看别人代码看了一天才知道.后面感觉也挺容易的,就是没想到,之前做过SPOJ 694 705求过不同子串了,知道怎么求不同子串个数了,但是比赛的时候这个技巧竟然抛在脑后了,然后就不会了. 但是今天自己用了自己的两个后缀数组的模板(倍增和DC3)的都WA了,搞得自己真想跳楼去了!! 到现在都不知道到底是哪里错了,处理的方法和标准做法都一样,但是就是WA,然后用了别人的模板,再用自己的处理方法就过了,怀疑自己的两个模板是不是哪里错

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