[HDU]3518——Boring counting

zhan.jiang.ou now faced a tough problem,his english teacher quan.hong.chun 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 aaaa as an example.”a” apears four times,”aa” apears two
times without overlaping.however,aaa can’t apear more than one time
without overlaping.since we can get “aaa” from [0-2](The position of
string begins with 0) and [1-3]. But the interval [0-2] and [1-3]
overlaps each other.So “aaa” can not take into account.Therefore,the
answer is 2(“a”,and “aa”).

题目大意:求一个字符串的不重叠子串的个数。

思路:我真是太辣鸡了,其实这个题就是后缀数组性质②的应用,只不过是求出每个长度的答案(性质详见我的后缀数组的基本使用技巧)!

总结:后缀数组英语应用太灵活,多回顾反思!

 1 #include<map>
 2 #include<set>
 3 #include<list>
 4 #include<deque>
 5 #include<cmath>
 6 #include<queue>
 7 #include<stack>
 8 #include<vector>
 9 #include<cstdio>
10 #include<complex>
11 #include<cstring>
12 #include<cstdlib>
13 #include<iostream>
14 #include<algorithm>
15 #define LL long long
16 #define db double
17 #define RG register
18 #define maxx 1001
19 #define Inf 666666
20 using namespace std;int tong[maxx];
21 int sa[maxx],X[maxx],Y[maxx],rnk[maxx],height[maxx],num[maxx];char s[maxx];
22 bool comp(int *r,int a,int b,int len){
23   return r[a]==r[b]&&r[a+len]==r[b+len];
24 }
25 void build_sa(int len){
26   int *x=X,*y=Y,*t,Max=maxx/2;
27   memset(tong,0,sizeof(tong));
28   for(int i=0;i<len;++i)
29     tong[x[i]=num[i]]++;
30   for(int i=1;i<=Max;++i)
31     tong[i]+=tong[i-1];
32   for(int i=len-1;i!=-1;i--)
33     sa[--tong[x[i]]]=i;
34   for(int j=1,p=1,i;p<len;j<<=1,Max=p){
35     for(i=len-1,p=0;i>=len-j;--i)y[p++]=i;
36     for(i=0;i<len;++i)
37       if(sa[i]>=j)y[p++]=sa[i]-j;
38     for(i=0;i<=Max;++i)
39       tong[i]=0;
40     for(i=0;i<len;++i)
41       tong[x[y[i]]]++;
42     for(i=1;i<Max;++i)
43       tong[i]+=tong[i-1];
44     for(i=len-1;i!=-1;i--)
45       sa[--tong[x[y[i]]]]=y[i];
46     for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<len;++i)
47       x[sa[i]]=comp(y,sa[i],sa[i-1],j)?p-1:p++;
48   }
49 }int n;
50 void geth(){
51   int j,k=0;
52   for(int i=1;i<=n;++i)
53     rnk[sa[i]]=i;
54   for(int i=0;i<n;height[rnk[i++]]=k)
55     for(k?k--:0,j=sa[rnk[i]-1];num[i+k]==num[j+k];k++);
56 }
57 void ans(){LL ans=0;
58   for(RG int len=1;len<=(n/2);++len){
59     int Max=-Inf,Min=Inf;
60       for(RG int i=1;i<=n;++i){
61     if(height[i]<len){
62       if(Max-Min>=len)ans++;
63       Max=-Inf,Min=Inf;
64     }
65     Max=max(Max,sa[i]);
66     Min=min(Min,sa[i]);
67     if(i==n&&Max-Min>=len)ans++;
68     }
69   }
70   printf("%lld\n",ans);
71 }
72 int main(){
73   while(scanf("%s",s)){
74     n=strlen(s);
75     if(n==1&&s[0]==‘#‘)break;
76     memset(rnk,0,sizeof(rnk));
77     memset(height,0,sizeof(height));
78     memset(sa,0,sizeof(sa));
79     memset(X,0,sizeof(X));
80     memset(Y,0,sizeof(Y));
81     for(int i=0;i<n;++i)
82       num[i]=s[i]-55;
83     num[n]=0;
84     build_sa(n+1);
85     geth();
86     ans();
87   }
88   return 0;
89 }
时间: 2024-12-28 08:53:46

[HDU]3518——Boring counting的相关文章

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

后缀数组 --- 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(后缀数组啊 求字符串中不重叠的重复出现至少两次的子串的个数)

题目链接: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 后缀数组LCP

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

hdu 3518 Boring counting 后缀数组 height分组

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

HDOJ 3518 Boring counting

SAM基本操作 拓扑求每个节点的  最左出现left,最右出现right,出现了几次num ...... 对于每一个出现两次以上的节点,对其所对应的一串子串的长度范围 [fa->len+1,len] 和其最大间距 right-left比较 即可...... Boring counting Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s):

HDOJ 题目3518 Boring counting(后缀数组,求不重叠重复次数最少为2的子串种类数)

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

HDU 4358 Boring counting(树状数组)

题意:  给定一棵树,每个节点有一个点权,然后有一些询问,求以某个点为根的子树中有多少的数出现了恰好k次. 思路: 首先dfs一次将树形结构转化成线性结构,利用时间戳记录下以结点u为根的子树在数组中的开始位置和结束位置. 那么我们将所有查询记录下来离线来做,将所有的查询按右端点升序排序. 考虑用树状数组来做这道题,每个位置记录当前从1到当前位置有多少数出现了恰好k次. 从头遍历一遍数组,map离散化记录每个值出现的位置,对于每个位置,如果值出现的次数t大于k,那么在将第t-k次出现的位置加一

【HDOJ】3518 Boring Counting

后缀数组2倍增可解. 1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 5 #define MAXN 1005 6 #define INF 0xfffff 7 #define MAXM 27 8 9 int wa[MAXN], wb[MAXN], ws[MAXN], wv[MAXN]; 10 char s[MAXN]; 11 int str[MAXN], sa[MAXN]; 12 int he