题意:让你找字符串有几个,字符串分为两种,一种是可以重叠的,另一种是不能重叠的。
在节点下开个0,1的标记,把cnt指针指向该标记,1的统计就是模板,0的统计只要看前一次统计时在原串的位置与当前位置只差是否大于等于长度
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std ;
const int maxn = 600006 ;
int *cnt[maxn] ;
class AC_auto
{
private :
int tot ;
int c[26][maxn] ;
int l[maxn] ;
int id[2][maxn] ;
int fail[maxn] ;
int v[maxn] ;
int pos[maxn] ;
queue<int> Q ;
int new_node ()
{
int i ;
for ( i = 0 ; i < 26 ; i ++ )
c[i][tot] = 0 ;
l[tot] = 0 ;
fail[tot] = v[tot] = id[0][tot] = id[1][tot] = 0 ;
pos[tot] = -1 ;
return tot ++ ;
}
public :
void init () { tot = 0 ; while ( !Q.empty () ) Q.pop () ; new_node () ; }
void insert ( char *s , int x , int t )
{
int now = 0 ;
int len = strlen ( s ) ;
for ( ; *s ; s ++ )
{
int k = *s - 'a' ;
if ( !c[k][now] ) c[k][now] = new_node () ;
now = c[k][now] ;
}
l[now] = len ;
v[now] = x ;
cnt[x] = &id[t][now] ;
}
void get_fail ()
{
int i , u = 0 , j , e ;
for ( i = 0 ; i < 26 ; i ++ ) if ( c[i][u] ) Q.push ( c[i][u] ) ;
while ( !Q.empty () )
{
u = Q.front () ;
Q.pop () ;
for ( i = 0 ; i < 26 ; i ++ )
{
if ( !c[i][u] )
{
c[i][u] = c[i][fail[u]] ;
continue ;
}
e = c[i][u] ;
j = fail[u] ;
fail[e] = c[i][j] ;
Q.push ( e ) ;
}
}
}
void work ( char *s , int flag )
{
int i , j , u = 0 , f ;
int n = strlen ( s ) ;
for ( i = 0 ; i < n ; i ++ )
{
int k = s[i] - 'a' ;
u = c[k][u] ;
j = u ;
while ( j )
{
if ( l[j] )
{
id[0][j] ++ ;
if ( i - l[j] >= pos[j] )
{
id[1][j] ++ ;
pos[j] = i ;
}
}
j = fail[j] ;
}
}
}
} ac ;
char s[maxn] ;
char s1[10] ;
int main ()
{
int cas = 0 ;
while ( scanf ( "%s" , s ) != EOF )
{
cas ++ ;
int n , i , p ;
ac.init () ;
scanf ( "%d" , &n ) ;
for ( i = 1 ; i <= n ; i ++ )
{
scanf ( "%d%s" , &p , s1 ) ;
ac.insert ( s1 , i , p ) ;
}
ac.get_fail () ;
ac.work ( s , 0 ) ;
printf ( "Case %d\n" , cas ) ;
for ( i = 1 ; i <= n ; i ++ )
printf ( "%d\n" , *cnt[i] ) ;
puts ( "" ) ;
}
}