HDU 3518 Boring counting
题目:Boring counting
链接:http://acm.hdu.edu.cn/showproblem.php?pid=3518
题意:给一个字符串,问有多少子串出现过两次以上,重叠不能算两次,比如ababa,aba只出现一次。
思路:
网上搜的题解估计大部分都是后缀数组,但字典树+优化是可以解决该问题的。
字典树解决这题难点就是内存,先不考虑内存,那么可以遍历起始点,然后添加入字典树,比如现在abab要添加进字典树,如果原本已经存在abab,并且两个不重叠,那么ans++,同时将abab标记掉,如果不存在,记录此时的下标以便等会判断是否重叠。(很简单的思路。)
现在解决内存,可以计算,如果要通过内存限制,字典树节点只能27万左右。但如果只设置这么大,最后会超出,会RE(G++好像会显示TLE),可以想象,字典树上很多节点的next[26]都是-1,浪费空间,因此可以把next[26]换成vector,动态申请,查找时多花一点时间遍历,但内存大大减小。
---------------------------------------------------------------------------------
下面是后缀数组解决该问题的方法:
首先要明白后缀数组里几个数组的用法,这里不详述了。
首先,我们可以遍历满足要求的字串的长度len,从1 到ls/2,然后遍历一遍height数组,height[i]表示排名第i 的后缀和排名第i-1 的后缀的最长公共前缀长度,那么如果height[i]>=len,这就有可能是答案了,只要不重叠就可以了,重叠可以用sa数组判断,可以找出最左边的下标记为l,最右边的下标记为r,只要l+len<=r就可以了,注意,height<len以后就是另外的字符串了。
AC代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<map> 4 #include<vector> 5 using namespace std; 6 struct Node 7 { 8 int val; 9 map<char,int> next; 10 }v[1000010]; 11 int vNum; 12 int ans; 13 void add(char *s,int start) 14 { 15 int p = 0; 16 for(int i=start;s[i];i++) 17 { 18 int t = v[p].next[s[i]]; 19 if(t!=0) p = t; 20 else 21 { 22 v[vNum].val=-1; 23 v[vNum].next.clear(); 24 v[p].next[s[i]]=vNum++; 25 p=vNum-1; 26 } 27 if(v[p].val!=-1) 28 { 29 if(v[p].val!=-2 && v[p].val<start) 30 { 31 ans++; 32 v[p].val=-2; 33 } 34 } 35 else v[p].val = i; 36 } 37 } 38 char s[1010]; 39 int main() 40 { 41 while(~scanf("%s",s)) 42 { 43 if(s[0]=='#') break; 44 v[0].val=-1; 45 for(int i=0;i<26;i++) v[0].next.clear(); 46 vNum=1; 47 ans=0; 48 for(int i=0;s[i];i++) 49 { 50 add(s,i); 51 } 52 printf("%d\n",ans); 53 } 54 return 0; 55 }
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 #include<math.h> 5 #include<set> 6 #include<map> 7 #include<list> 8 #include<stack> 9 #include<queue> 10 #include<vector> 11 #include<string> 12 #include<algorithm> 13 using namespace std; 14 #define lson rt<<1 15 #define rson rt<<1|1 16 #define N 1010 17 #define M 100010 18 #define Mod 1000000007 19 #define LL long long 20 #define INF 0x7fffffff 21 #define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;i++) 22 #define For(i,f_start,f_end) for(int i=f_start;i<f_end;i++) 23 #define REP(i,f_end,f_start) for(int i=f_end;i>=f_start;i--) 24 #define Rep(i,f_end,f_start) for(int i=f_end;i>f_start;i--) 25 #define MT(x,i) memset(x,i,sizeof(x)) 26 #define gcd(x,y) __gcd(x,y) 27 const double PI = acos(-1); 28 29 char s1[1010]; 30 int ws[N],wv[N]; 31 int sa[N],r[N],wx[N],wy[N]; 32 int height[N]; 33 bool cmp(int *r,int a,int b,int l) 34 { 35 return r[a]==r[b]&&r[a+l]==r[b+l]; 36 } 37 void da(int *r,int n,int m) 38 { 39 int *x=wx,*y=wy; 40 for(int i=0;i<m;i++) ws[i]=0; 41 for(int i=0;i<n;i++) ws[x[i]=r[i]]++; 42 for(int i=1;i<m;i++) ws[i]+=ws[i-1]; 43 for(int i=n-1;i>=0;i--) sa[--ws[x[i]]]=i; 44 int i,j,p,*t; 45 for(j=1,p=1;p<n;j*=2,m=p) 46 { 47 for(p=0,i=n-j;i<n;i++) y[p++]=i; 48 for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j; 49 for(i=0;i<n;i++) wv[i]=x[y[i]]; 50 for(i=0;i<m;i++) ws[i]=0; 51 for(i=0;i<n;i++) ws[wv[i]]++; 52 for(i=1;i<m;i++) ws[i]+=ws[i-1]; 53 for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i]; 54 for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++) 55 x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++; 56 } 57 for(int i=0;i<n;i++) 58 { 59 r[sa[i]]=i; 60 } 61 } 62 void calHeight(int n) 63 { 64 int h=0; 65 for(int i=0;i<n;i++) 66 { 67 if(r[i]==0) h=0; 68 else 69 { 70 int k=sa[r[i]-1]; 71 if(--h<0) h=0; 72 while(s1[k+h]==s1[i+h]) h++; 73 } 74 height[r[i]]=h; 75 } 76 } 77 78 int main() 79 { 80 while(~scanf("%s",s1)) 81 { 82 if(s1[0]=='#') break; 83 int ls = strlen(s1); 84 for(int i=0;i<ls;i++) 85 { 86 r[i]=s1[i]-'a'+1; 87 } 88 r[ls++]=0; 89 da(r,ls,27); 90 calHeight(ls); 91 int ans = 0; 92 for(int i=1;i<=(ls-1)/2;i++) 93 { 94 int flag = 0; 95 int l=INF,r=-1; 96 for(int j=2;j<ls;j++) 97 { 98 if(height[j]>=i) 99 { 100 l = min(sa[j],min(sa[j-1],l)); 101 r = max(sa[j],max(sa[j-1],r)); 102 if(flag==0&&l+i<=r) 103 { 104 ans++; 105 flag=1; 106 } 107 } 108 else 109 { 110 flag=0; 111 l=INF; 112 r=-1; 113 } 114 } 115 } 116 printf("%d\n",ans); 117 } 118 return 0; 119 }