hdu 3518 (접미사 배열)

26268 단어 접미사 배열
제목 설명: 한 문자열 에 적어도 두 번 반복 되 는 문자열 의 개 수 를 찾 습 니 다.
  code:
     접미사 배열 처리, height 를 찾 습 니 다...  블 로 거들 의 상세 한 코드 사고방식 참고
  1     #include<iostream>

  2     #include<string>

  3     using namespace std;

  4     #define N 1200

  5     string s;

  6     int n, sa[4*N], rank[N], height[N];

  7     int buf[4*N], ct[N], sx[N], sax[N];

  8     inline bool leq(int a, int b, int x, int y)

  9     {

 10         return (a < x || a == x && b <= y);

 11     }

 12     inline bool leq(int a, int b, int c, int x, int y, int z)

 13     {

 14         return (a < x || a == x && leq(b, c, y, z));

 15     }

 16     inline int geti(int t, int nx, int sa[])

 17     {

 18         return (sa[t]<nx ? sa[t]*3+1 : (sa[t]-nx)*3+2);

 19     }

 20         //    

 21     static void radix(int a[], int b[], int s[], int n, int k)

 22     { // sort a[0..n-1] to b[0..n-1] with keys in 0..k from s

 23         int i, t, sum;

 24         memset(ct, 0, (k + 1) * sizeof(int));

 25         for (i = 0; i < n; ++i) ct[s[a[i]]]++;

 26         for (i = 0, sum = 0; i <= k; ++i)

 27         {

 28             t = ct[i]; ct[i] = sum; sum += t;

 29         }

 30         for (i = 0; i < n; i++) b[ct[s[a[i]]]++] = a[i];

 31     }

 32 

 33     /*

 34         ,               O(nlogn)。

 35  36     int *r:          r     ,   r[0]   r[n-1] ,     n ,        m 。

 37              ,   r[n-1]      r[i]     0, r[n-1]=0 。

 38     int *sa:     ,     sa    ,  sa[0]   sa[n-1] 。 

 39     */

 40     void suffix(int s[], int sa[], int n, int k)

 41     { // !!! require s[n] = s[n+1] = s[n+2] = 0, n >= 2.

 42         int i, j, e, p, t;

 43         int name = 0, cx = -1, cy = -1, cz = -1;

 44         int nx = (n+2)/3, ny = (n+1)/3, nz = n/3, nxz = nx+nz;

 45         int *syz = s + n + 3, *sayz = sa + n + 3;

 46         for (i=0, j=0; i < n + (nx - ny); i++)

 47         if (i%3 != 0) syz[j++] = i;

 48         radix(syz , sayz, s+2, nxz, k);

 49         radix(sayz, syz , s+1, nxz, k);

 50         radix(syz , sayz, s , nxz, k);

 51         for (i = 0; i < nxz; i++)

 52         {

 53             if (s[ sayz[i] ] != cx || s[ sayz[i] + 1 ] != cy ||s[ sayz[i] + 2 ] != cz)

 54             {

 55                 name++; cx = s[ sayz[i] ];

 56                 cy = s[ sayz[i] + 1 ]; cz = s[ sayz[i] + 2 ];

 57             }

 58             if (sayz[i] % 3 == 1) syz[ sayz[i] / 3 ] = name;

 59             else syz[ sayz[i]/3 + nx ] = name;

 60         }

 61         if (name < nxz)

 62         {

 63             suffix(syz, sayz, nxz, name);

 64             for (i = 0; i < nxz; i++) syz[sayz[i]] = i + 1;

 65         }

 66         else

 67         {

 68             for (i = 0; i < nxz; i++) sayz[syz[i] - 1] = i;

 69         }

 70         for (i = j = 0; i < nxz; i++)

 71         if (sayz[i] < nx) sx[j++] = 3 * sayz[i];

 72         radix(sx, sax, s, nx, k);

 73         for (p=0, t=nx-ny, e=0; e < n; e++)

 74         {

 75             i = geti(t, nx, sayz); j = sax[p];

 76             if ( sayz[t] < nx ?leq(s[i], syz[sayz[t]+nx], s[j], syz[j/3]) :

 77                 leq(s[i], s[i+1], syz[sayz[t]-nx+1],

 78             s[j], s[j+1], syz[j/3+nx]) )

 79             {

 80                 sa[e] = i;

 81                 if (++t == nxz)

 82                 {

 83                     for (e++; p < nx; p++, e++)

 84                     sa[e] = sax[p];

 85                 }

 86             }

 87             else

 88             {

 89                 sa[e] = j;

 90                 if (++p == nx) for (++e; t < nxz; ++t, ++e)

 91                 sa[e] = geti(t, nx, sayz);

 92             }

 93         }

 94     }

 95 

 96     /*

 97          SA        ,    1..n      SA[1],SA[2],……,SA[n],

 98          Suffix(SA[i]) < Suffix(SA[i+1]) , 1 ≤ i<n 。

 99          S   n                               SA  。 

100     */

101     void makesa()

102     {

103         memset(buf, 0, 4 * n * sizeof(int));

104         memset(sa, 0, 4 * n * sizeof(int));

105         for (int i=0; i<n; ++i) buf[i] = s[i] & 0xff;

106         suffix(buf, sa, n, 255);

107     }

108 

109 

110 

111     /*

112          Rank[i]      Suffix(i)                “    ” 。

113         ,              。

114              n 。

115             ,              ,                ,           。

116             ,     O(1)               。

117                         ,     O(n)          。

118                   ,         n  ,           n           “    ” 。 

119     */

120     void getRank()

121     {

122         for(int i = 1;i < n; ++ i)

123             rank[sa[i]] = i;

124     }

125     /*

126           u,v    lcp(u,v)=max{i|u=iv},           u v     ,             ,

127 128         i,j  LCP(i,j)=lcp(Suffix(SA[i]),Suffix(SA[j])),  i,j  1 n   。LCP(i,j)         i 

129       j             。

130           height, height[i]=LCP(i-1,i),1<i≤n,  height[1]=0。

131     */

132     void lcp()

133     { // O(4 * N)

134         int i, j, k;

135         for (j = rank[height[i=k=0]=0]; i < n - 1; i++, k++)

136             while (k >= 0 && s[i] != s[ sa[j-1] + k ])

137                 height[j] = (k--), j = rank[ sa[j] + 1 ];

138     }

139     int main()

140     {

141 

142         while(cin>>s && s[0] != '#')

143         {

144             n = s.length() + 1;

145             makesa();

146             getRank();

147             lcp();

148             int ans = 0, minid, maxid;

149             //      h

150             for(int i = 1; i <= (n >> 1); i++)

151             {

152                 minid = 1200, maxid = -1;

153                 //      h,  height  ,     height    h             l r。

154                 for(int j = 2; j < n; j++)

155                     if (height[j] >= i)

156                     {

157                         if (sa[j - 1] < minid) minid = sa[j - 1];

158                         if (sa[j - 1] > maxid) maxid = sa[j - 1];

159                         if (sa[j] < minid) minid = sa[j];

160                         if (sa[j] > maxid) maxid = sa[j];

161                     }

162                     else

163                     {

164                         //  l + h - 1 < r  ,      ,   1.

165                         if (maxid != -1 && minid + i <= maxid) ans++;

166                         minid = 1200, maxid = -1;

167                     }

168                 //  l + h - 1 < r  ,      ,   1.

169                 if (maxid != -1 && minid + i <= maxid) ans++;

170             }

171            cout<<ans<<endl;

172         }

173         return 0;

174     }

좋은 웹페이지 즐겨찾기