hdu_3518_Boring counting(后缀数组)

题目链接:hdu_3518_Boring counting

题意:

给你一个字符串,让你找不重叠且出现大于1次以上的字串个数

题解:

后缀数组height数组的应用,我们枚举字串的长度,然后将height数组分段,符合条件就ans++

为什么要这样做,因为height数组存的是相邻排名后缀的最大前缀数,如果height的值大于等于我们枚举的长度len,

那么有可能这一段存在有两个以上的该长度的字串,然后我们统计这个段的开头长度l和结束长度r,如果r-l>=len,说明这段必有

大于一个以上的该长度的相同子串,因为我们每次都是枚举len,按len分的段,所以不会重复。

 1 #include<bits/stdc++.h>
 2 #define F(i,a,b) for(int i=a;i<=b;++i)
 3 using namespace std;
 4
 5 namespace suffixarray{
 6     #define FN(n) for(int i=0;i<n;i++)
 7     const int N =1E3+7;
 8     int rnk[N],sa[N],height[N],c[N];char s[N];
 9     void getsa(int n,int m,int *x=rnk,int *y=height){
10         FN(m)c[i]=0;FN(n)c[x[i]=s[i]]++;FN(m)c[i+1]+=c[i];
11         for(int i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
12         for(int k=1,p;p=0,k<=n;k=p>=n?N:k<<1,m=p){
13             for(int i=n-k;i<n;i++)y[p++]=i;
14             FN(n)if(sa[i]>=k)y[p++]=sa[i]-k;
15             FN(m)c[i]=0;FN(n)c[x[y[i]]]++;FN(m)c[i+1]+=c[i];
16             for(int i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
17             swap(x,y),p=1,x[sa[0]]=0;
18             for(int i=1;i<n;i++)
19             x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
20         }
21         FN(n)rnk[sa[i]]=i;
22         for(int i=0,j,k=0;i<n-1;height[rnk[i++]]=k)
23         for(k=k?k-1:k,j=sa[rnk[i]-1];s[i+k]==s[j+k];k++);
24     }
25 }
26
27 inline void upd(int &a,int b){if(a>b)a=b;}
28 inline void upu(int &a,int b){if(a<b)a=b;}
29
30 using namespace suffixarray;
31 int main(){
32     while(~scanf("%s",s))
33     {
34         if(s[0]==‘#‘)break;
35         int len=strlen(s),ans=0;
36         getsa(len+1,128);
37         F(i,1,len)
38         {
39             int l=len+1,r=0;
40             F(j,1,len)
41             {
42                 if(height[j]>=i)upd(l,sa[j]),upu(r,sa[j]);
43                 else
44                 {
45                     if(r-l>=i)ans++;
46                     l=r=sa[j];
47                 }
48             }
49             if(r-l>=i)ans++;
50         }
51         printf("%d\n",ans);
52     }
53     return 0;
54 }

时间: 2024-08-03 16:34:01

hdu_3518_Boring counting(后缀数组)的相关文章

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数

hdu3518---Boring counting(后缀数组,对后缀分组)

Problem Description 035 now faced a tough problem,his english teacher gives him a string,which consists with n lower case letter,he must figure out how many substrings appear at least twice,moreover,such apearances can not overlap each other. Take aa

hdu 3518 Boring counting 后缀数组 height分组

题目链接 题意 对于给定的字符串,求有多少个 不重叠的子串 出现次数 \(\geq 2\). 思路 枚举子串长度 \(len\),以此作为分界值来对 \(height\) 值进行划分. 显然,对于每一组,组内子串具有一个长度为 \(len\) 的公共前缀. 至于是否重叠,只需判断 \(sa_{max}-sa_{min}\geq len\). 对于组间,显然它们的公共前缀互不相同,所以答案即为\(\sum_{len}\sum_{group}\) Code #include <bits/stdc++

后缀数组 --- HDU 3518 Boring counting

Boring counting Problem's Link:   http://acm.hdu.edu.cn/showproblem.php?pid=3518 Mean: 给你一个字符串,让你求出有多少个子串(无重叠)至少出现了两次. analyse: 后缀数组中height数组的运用,一般这个数组用得很少. 总体思路:分组统计的思想:将相同前缀的后缀分在一个组,然后对于1到len/2的每一个固定长度进行统计ans. 首先我们先求一遍后缀数组,并把height数组求出来.height数组代表的

hdu 3518 Boring counting(后缀数组)

Boring counting                                                                       Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Problem Description 035 now faced a tough problem,his english teacher gives him

Boring counting HDU - 3518 (后缀数组)

Boring counting \[ Time Limit: 1000 ms \quad Memory Limit: 32768 kB \] 题意 给出一个字符串,求出其中出现两次及以上的子串个数,要求子串之间不可以重合. 思路 对字符串后缀数组,然后枚举子串长度 \(len\),若某一段连续的 \(sa[i]\) 的 \(lcp \geq len\),那么说明这一段内存在一个长度为 \(lcp\) 的子串,而我们只需要其中的前 \(len\) 部分,接下来只要找出这个子串出现的最左和最右位置,

HDU 3518 Boring counting(后缀数组啊 求字符串中不重叠的重复出现至少两次的子串的个数)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3518 Problem Description 035 now faced a tough problem,his english teacher gives him a string,which consists with n lower case letter,he must figure out how many substrings appear at least twice,moreover

hdu 3518 后缀数组

Boring counting Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 2906    Accepted Submission(s): 1201 Problem Description 035 now faced a tough problem,his english teacher gives him a string,whic

bnuoj 34990(后缀数组 或 hash+二分)

后缀数组倍增算法超时,听说用3DC可以勉强过,不愿写了,直接用hash+二分求出log(n)的时间查询两个字符串之间的任意两个位置的最长前缀. 我自己在想hash的时候一直在考虑hash成数值时MOD取多大,如果取10^18的话,那么两数相乘个就超LL了,但是取10^9的话又怕出现重复的可能大.后面才发现自己是sb,如果用unsigned long long 如果有溢出或者为负数是直接变成对(1<<64)取模了. 也就是无符号长整形运算自动帮你取模了.所以可以放心用hash Justice S