lightoj 1427 Substring Frequency (II) (ac自动机)
题意:求每个模式串在母串中出现的次数。
解题思路:ac自动机(显然)。类似模板题,但是这题查询的时候不能一直沿着fail边走,而是要用到fail树上的拓扑,最后dp往上推。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std ;
const int maxn = 500*500 ;
char s1[1111111] , s2[maxn] ;
struct ac_auto {
int c[maxn][26] , tot , fail[maxn] ;
int st[maxn] , top , val[maxn] ;
int pos[maxn] ;
inline int new_node () {
int i ;
val[tot] = fail[tot] = 0 ;
memset(c[tot], 0, sizeof(c[tot]));
return tot ++ ;
}
void init () {
tot = top = 0 ;
new_node () ;
}
void insert ( char *s , int id ) {
int now = 0 ;
for ( ; *s ; s ++ ) {
int k = *s - 'a' ;
if ( !c[now][k] ) c[now][k] = new_node () ;
now = c[now][k] ;
}
pos[id] = now ;
}
void get_fail () {
queue<int> Q ;
int u = 0 , i , j ,e ;
for ( i = 0 ; i < 26 ; i ++ ) {
if ( c[u][i] ) Q.push ( c[u][i] ) ;
// st[++top] = c[i][u] ;
}
while ( !Q.empty () ) {
u = Q.front () , Q.pop () ;
for ( i = 0 ; i < 26 ; i ++ ) {
if ( c[u][i] ) {
e = c[u][i] ;
j = fail[u] ;
fail[e] = c[j][i];
Q.push ( e ) ;
st[++top] = e ;
}
else c[u][i] = c[fail[u]][i] ;
}
}
}
void solve ( char *s , int n ) {
int now = 0 ;
int i ;
for ( ; *s ; s ++ ) {
int k = *s - 'a' ;
now = c[now][k] ;
val[now] ++ ;
}
while ( top ) {
int p = st[top] ;
val[fail[p]] += val[p] ;
top -- ;
}
for ( i = 1 ; i <= n ; i ++ )
printf ( "%d\n" , val[pos[i]] ) ;
}
} ac ;
int main () {
int cas , ca = 0 , n , i ;
scanf ( "%d" , &cas ) ;
while ( cas -- ) {
scanf ( "%d" , &n ) ;
scanf ( "%s" , s1 ) ;
ac.init () ;
for ( i = 1 ; i <= n ; i ++ ) {
scanf ( "%s" , s2 ) ;
ac.insert ( s2 , i ) ;
}
ac.get_fail () ;
printf ( "Case %d:\n" , ++ ca ) ;
ac.solve ( s1 , n ) ;
}
}