acm-字符串整理

时间:2022-12-30 13:49:47
acm-字符串整理acm-字符串整理
  1 一、后缀数组
2 #define maxn 200015
3 int wa[maxn],wb[maxn],wv[maxn],WS[maxn];
4 int len, sa[maxn] ;
5 inline void swap(int &x, int &y) { int t = x ; x = y ; y = t ; }
6 inline int min(int x, int y) {return x < y ? x : y ; }
7 inline int max(int x, int y) {return x > y ? x : y ; }
8 inline int cmp(int *r,int a,int b,int l) {return r[a]==r[b]&&r[a+l]==r[b+l];}
9 void da(int *r,int *sa,int n,int m){
10 int i,j,p,*x=wa,*y=wb,*t;
11 for(i=0;i<m;i++) WS[i]=0;
12 for(i=0;i<n;i++) WS[x[i]=r[i]]++;
13 for(i=1;i<m;i++) WS[i]+=WS[i-1];
14 for(i=n-1;i>=0;i--) sa[--WS[x[i]]]=i;
15 for(j=1,p=1;p<n;j*=2,m=p)
16 {
17 for(p=0,i=n-j;i<n;i++) y[p++]=i;
18 for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
19 for(i=0;i<n;i++) wv[i]=x[y[i]];
20 for(i=0;i<m;i++) WS[i]=0;
21 for(i=0;i<n;i++) WS[wv[i]]++;
22 for(i=1;i<m;i++) WS[i]+=WS[i-1];
23 for(i=n-1;i>=0;i--) sa[--WS[wv[i]]]=y[i];
24 for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
25 x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
26 }
27 return;
28 }
29 int Rank[maxn], height[maxn];
30 int s[maxn] ;
31 void calheight(int *r,int *sa,int n){
32 int i,j,k=0;
33 for(i=1;i<=n;i++) Rank[sa[i]]=i;
34 for(i=0;i<n;height[Rank[i++]]=k)
35 for(k?k--:0,j=sa[Rank[i]-1];r[i+k]==r[j+k];k++);
36 }int lsa[maxn], tmp[maxn] ;
37 void init_SA(){
38 int i, t ;
39 for(len = 0 ; A[len] ; len ++) s[len] = static_cast<int>(A[len]) ;
40 s[len] = 0 ;
41 da(s, sa, len+1, 259) ;
42 calheight(s, sa, len) ;
43 }
44
45 二、KMP & Manancher
46 1.模板
47 void getNext() {
48 int j = 0 , k = -1 ;
49 next[0] = -1 ;
50 while(j < tl ) // next[i] = max {j | t[i, j] == t[i+1 - j, i] } ;
51 {
52 if(k == -1 || t[j] == t[k] ) next[ ++j] = ++ k ;
53 else k = next[k] ;
54 }
55 }
56 int kmp_Index(){
57 int l = -1, r = sl ;
58 int i = 0 , j = 0 ;
59 while(i < sl && j < tl )
60 {
61 if(j == -1 || s[i] == t[j] )
62 {
63 if(!j ) l = i ;
64 else if(j == tl-1) r = i ;
65 i ++ ; j ++ ;
66 }
67 else j = next[j] ;
68 }
69 printf("%d %d\n", l, r ) ;
70 if(j == tl ) return i - tl ;
71 else return -1 ;
72 }
73 int kmp_Count(){
74 int ans = 0 ;
75 int i, j ;
76 if(sl == 1 && tl == 1)
77 {
78 if(s[0] == t[0] ) return 1 ;
79 else return 0 ;
80 }
81 for(i = 0, j = 0 ; i < sl ; i ++ )
82 {
83 while(j > 0 && s[i] != t[j] ) j = next[j] ;
84 if(s[i] == t[j] ) j ++ ;
85 if(j == tl )
86 {
87 ans ++ ;
88 j = next[j] ; // 提前更新,防治t数组越界 ;
89 }
90 }
91 return ans ;
92 }
93 2.字符串周期
94 int solve(){
95 for(i = 1 ; i <= n ; i ++ ){
96 len = i - next[i] ;
97 if(next[i] && !(i % len ) ) printf("%d %d\n", i , i / len ) ; //
98 }
99 }
100 3.T与S[i,n]的最长公共前缀
101 //extend[i] 数组表示T 与 S[i , n -1] 的最长公共前缀 ;
102 void build_Next(){
103 int k, q, p, a ;
104 next[0] = n ;
105 for (k = 1 , q = -1 ; k < n ; k ++, q --)
106 {
107 if (q < 0 || k + next[k - a] >= p)
108 {
109 if (q < 0 ) q = 0 , p = k ;
110 //q是B串继续向后匹配的指针,p是A串继续向后匹配的指针,
111 也是曾经到达过的最远位置+1
112 //q在每次计算后会减小1,直观的讲就是B串向后错了一位
113 while (p < n && t[p] == t[q]) p ++, q ++ ;
114 next[k] = q, a = k ;
115 }
116 else next[k] = next[k - a] ;
117 }
118 }
119 void extend_KMP(){
120 int k, q, p, a;
121 for (k = 0, q = -1; k < n ; k ++, q --)
122 {
123 if (q < 0 || k + next[k - a] >= p)
124 {
125 if (q < 0) q = 0, p = k ;
126 while (p < n && q < n && s[p] == t[q])
127 {
128 p ++ ;
129 q ++ ;
130 }
131 extend[k] = q ;
132 a = k ;
133 }
134 else extend[k] = next[k - a];
135 }
136 }
137 /*void ExtendKmp(char ss[],int ls,char tt[],int lt){// 直接调用;
138 int i,j,k;
139 int Len,L;
140 j=0;
141 while(tt[j+1]==tt[j]&&j+1<lt) j++;
142 next[1]=j,k=1;
143 for(i=2;i<lt;i++){
144 Len=k+next[k],L=next[i-k];
145 if(Len>L+i) next[i]=L;
146 else{
147 j=Len-i>0?Len-i:0;
148 while(tt[i+j]==tt[j]&&i+j<lt) j++;
149 next[i]=j,k=i;
150 }
151 }
152 j=0;
153 while(ss[j]==tt[j]&&j<lt&&j<ls) j++;
154 extend[0]=j,k=0;
155 for(i=1;i<ls;i++){
156 Len=k+extend[k],L=next[i-k];
157 if(Len>L+i) extend[i]=L;
158 else{
159 j=Len-i>0?Len-i:0;
160 while(ss[i+j]==tt[j]&&i+j<ls&&j<lt) j++;
161 extend[i]=j,k=i;
162 }
163 }
164 } */
165 4.Manancger算法
166 void initStr(){ // 将原字符串a 转化为加了'#'号的字符串 s,
167 // 将问题全转化为“长度都为奇数”的情况;
168 int i , n = strlen(a) ;
169 for(i = 1 ; i <= n ; i ++ )
170 {
171 s[2*i] = a[i-1] ;
172 s[2*i + 1 ] = '#' ;
173 }
174 s[2*i] = '\0' ;
175 }
176 void manacherMaxPali(){
177 int i , mx = 0 , r = 0 , id = 0 , ri ; // mx 表示s[i]前面所有回文字串的最右端 ,
178 for(i = 1 ; i < len ; i ++ )// id 表示取得mx时对应 s 中的位置 ;
179 {// p[i] = min{ p[id - (i-id) ] , mx - i },求出最小的可能值;
180 if(mx > i ) p[i] = getMin(p[2*id - i ] , mx - i ) ;
181 else p[i] = 1 ;
182 // 检测p[i]能否继续增加 ;
183 for(; s[i - p[i] ] == s[i + p[i] ] ; p[i] ++ ) ;
184 if(i + p[i] > mx ) //更新 mx 及 id ;
185 {
186 mx = i + p[i] ;
187 id = i ;
188 }
189 if(r < p[i] )
190 {
191 r = p[i] ;
192 ri = i ;
193 }
194 }
195 int b = ri - r + 1;
196 for(i = b ; i < ri + r ; i ++ ) if(s[i] != '#' ) printf("%c", s[i]) ;printf("\n") ;
197 }
198 三、AC Automation
199 struct Node{
200 int c ;
201 Node * f, *next[26] ;
202 Node(){
203 memset(next, NULL, sizeof(next)) ;
204 c = 0 ; f = NULL ;
205 }
206 } *que[QMAXN] ;
207 char kw[51], str[MAXN] ;
208 void insert(Node *rt, char s[]){
209 int index, i = 0 ;
210 Node *p = rt ;
211 while(s[i]){
212 index = s[i]-'a' ;
213 if(p->next[index] == NULL) p->next[index] = new Node() ;
214 p = p->next[index] ;
215 i ++ ;
216 }
217 (p->c) ++ ;
218 }
219 void getFail(Node * rt){
220 Node *tmp, *p ;
221 int rear = 0, front = 0 ;
222 rt->f = NULL ;
223 que[rear++] = rt ;
224 while(rear != front){
225 tmp = que[front++] ; //取出已经更新的节点,更新它的所有孩子节点;
226 for(int i = 0 ; i < 26 ; i ++)
227 {
228 if(tmp->next[i] == NULL) continue ;
229 if(tmp == rt) tmp->next[i]->f = rt ;
230 //假设第一层的所有节点fail指针指向根节点;
231 else //如果不是第一层的,则从父节点的失败指针开始找到一个节点p:
232 该节点具有有含有i字符的子节点p->next[i];
233 { //因为当前指针与p匹配,则其孩子节点就应该p->next[i]匹配;
234 for(p = tmp->f ; p && (p->next[i] == NULL) ; p = p->f) ;
235 tmp->next[i]->f = (p == NULL) ? rt : p->next[i] ;
236 }
237 que[rear++] = tmp->next[i] ; //将已更新的子节点入队列;
238 }
239 }
240 }
241 int query(Node * rt){
242 int i = 0, count = 0, index ;
243 Node *tmp, *p = rt ;
244 while(str[i])
245 {
246 index = str[i] - 'a' ;//如果当前节点不能匹配,且又不是root,则找失败指针;root失败指针为NULL;
247 while(p->next[index] == NULL && p != rt) p = p->f ;
248 p = p->next[index] ; //继续匹配;
249 if(p == NULL) p = rt ; //说明上一轮匹配结束,重新开始匹配;
250 tmp = p ;
251 while(tmp != rt && tmp->c != -1)
252 {
253 count += tmp->c ;
254 tmp->c = -1 ; //说明已经遍历过了;
255 tmp= tmp->f ; //这时,如果tmp失败节点如果是单词结尾的话也要考虑;
256 }
257 i++ ;
258 }
259 return count ;
260 }
261 int solve(){
262 Node * root ;
263 while(T --)
264 {
265 root = new Node() ;
266 scanf("%d", &n) ;
267 for(i = 1 ; i <= n ; i ++){scanf("%s", kw) ;insert(root, kw) ;}
268 getFail(root) ;scanf("%s", str) ;
269 printf("%d\n", query(root)) ;
270 }
271 四、后缀自动机
272 /*****************后缀自动机模板**************************************/
273 const int Smaxn = 26 ; const int maxn = 4010 ;
274 struct node{
275 node *par,*go[Smaxn];
276 int num, val ;
277 }*root,*tail,que[maxn],*top[maxn];
278 int tot, len ;
279 void add(int c,int l){
280 node *p=tail,*np=&que[tot++];
281 np->val=l;
282 while(p&&p->go[c]==NULL)
283 p->go[c]=np,p=p->par;
284 if(p==NULL) np->par=root;
285 else
286 {
287 node *q=p->go[c];
288 if(p->val+1==q->val) np->par=q;
289 else
290 {
291 node *nq=&que[tot++];
292 *nq=*q;
293 nq->val=p->val+1 ;
294 np->par=q->par=nq;
295 while(p&&p->go[c]==q) p->go[c]=nq,p=p->par;
296 }
297 }
298 tail=np;
299 }
300 void init(){
301 memset(que,0,sizeof(que));
302 tot=0 ;
303 len = 1 ;
304 root = tail= &que[tot++] ;
305 }
View Code