zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",ans);
    117   }
    118   return 0;
    119 }
    后缀数组
  • 相关阅读:
    用欧拉公式推导三角函数所有公式包括 倍角公式-半角公式-和差化积-积化和差
    20161006-git学习笔记
    十五的学习日记20160925
    十五的学习日记20160926-你不知道的JS笔记/
    十五的学习日记20160927-ES6学习/中间变量/数组坑/
    十五的学习日记20160928-扑克牌/目标/Apache外网访问
    十五的学习日记20160929-click300毫秒延迟/requestAnimationFrame/帧率
    十五的学习日记20160930-jquery/ajax/JS引擎/job queue
    十五的学习日记20161001-insertAdjacentHTML与insertAdjacentText
    传入评分 返回整数和小数 页面拼接 --------------20160705
  • 原文地址:https://www.cnblogs.com/hchlqlz-oj-mrj/p/6004453.html
Copyright © 2011-2022 走看看