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 }
后缀数组

 

posted @ 2016-10-27 16:27  hchlqlz  阅读(210)  评论(0编辑  收藏  举报