大致问题是给你两个串,S与T,要求求S有多少子串与T匹配。匹配定义为两个串大写字母位置及内容一模一样,小写字母是可替换的。详见样例
Input
3 //数据组数
AiBjCiDECjDiFGC
AaBiCaDECiDaFGC
cDEcDEbDE
aDEbDE
ccddef
aab
Output
1
1
2
这题可以用Hash解决
对于小写字母,我们记录一个小写字母与上一个和它相同的小写字母的距离la[],和下一个与他相同的小写字母的距离nx[]。
先把T串的nx[]给hash起来。
再在S串线性扫一遍,维护长度为|T|的子串hash值。即加入一个新小写字母要将他上一个与他相同小写字母在hash值里的位置赋上值。
大写字母的hash值就是MAX_nx[]~MAX_nx[]+26
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std ;
typedef long long ull ;
int Q , i , j , k , n , m , l[2] ;
ull hs[2][3] , mo[3] = { 128760641,100000081 , 1196033 } ;
char s[2][1000010] ;
struct node {
int la , nx ;// all record posi of changing
}d[2][1000010] ;
int w[27] ;
void Preprocess( int p , int n ) {
int i , j , k ;
memset( w , 255 , sizeof w ) ;
memset( d[p] , 0 , sizeof d[p] ) ;
for( i=0 ; i<n ; i++ ) {
if( s[p][i] > 'Z' ) {
if( w[ s[p][i] - 'a' ]!=-1 ) d[p][i].la = i - w[ s[p][i] - 'a' ] ,
d[p][ w[ s[p][i] - 'a' ] ].nx = i - w[ s[p][i] - 'a' ] ;
w[ s[p][i] - 'a' ] = i ;
}
}
}
// We communi that 0 ~ l[1]-1 is lowercase letter posi changing , while l[1]+25 uppercase letter . And we should x( l[1]+26 )
ull Eraser[1000010] , X ;
void Hashize( int p , int n ) {
int i , j , k ;
ull ret[3] ;
memset( ret , 0 , sizeof ret ) ;
for( i=0 ; i<n ; i++ ) {
for( k=0 ; k<3 ; k++ ) ret[k] = ret[k] * X % mo[k] ;
if( s[p][i] > 'Z' ) {
if( i + d[p][i].nx < n ) {
for( k=0 ; k<3 ; k++ ) ret[k] = ( ret[k] + d[p][i].nx ) % mo[k] ;
Eraser[i] = d[p][i].nx ;
}
} else {
for( k=0 ; k<3 ; k++ ) ret[k] = ( ret[k] + l[1] + s[p][i] - 'A' ) % mo[k] ;
Eraser[i] = l[1] + s[p][i] - 'A' ;
}
}
for( k=0 ; k<3 ; k++ ) hs[p][k] = ret[k] ;
}
ull inx[1000010][3] ;
int main() {
scanf("%d" , &Q ) ;
while( Q-- ) {
scanf("%s%s",s[0] , s[1] ) ;
l[0] = strlen( s[0] ) , l[1] = strlen( s[1] ) ;
Preprocess( 0 , l[0] ) ;
Preprocess( 1 , l[1] ) ;
X = ( l[1] + 26 ) ;
Hashize( 1 , l[1] ) ;
memset( Eraser , 0 , sizeof Eraser ) ;
Hashize( 0 , l[1] ) ;
for( inx[0][0] = inx[0][1] = inx[0][2] = 1 , i = 1 ; i<=l[0] ; i++ )
for( k=0 ; k<3 ; k++ ) inx[i][k] = inx[i-1][k] * X % mo[k];
int ans = 0 ;
if( hs[0][0]==hs[1][0] && hs[0][1]==hs[1][1] && hs[0][2]==hs[1][2] ) ans ++ ;
for( i=l[1] ; i<l[0] ; i++ ) {
for( k=0 ; k<3 ; k++ ) hs[0][k] = ( ( hs[0][k] - inx[ l[1]-1 ][k] * Eraser[ i-l[1] ] ) % mo[k] + mo[k] ) % mo[k];
for( k=0 ; k<3 ; k++ ) hs[0][k] = hs[0][k] * X % mo[k];
if( s[0][i] >'Z' ) {
if( d[0][i].la<l[1] ) {
for( k=0 ; k<3 ; k++ ) hs[0][k] = ( hs[0][k] + ( Eraser[ i-d[0][i].la ] = d[0][i].la ) * inx[ d[0][i].la ][k] ) % mo[k] ;
}
} else {
for( k=0 ; k<3 ; k++ ) hs[0][k] = ( hs[0][k] + ( Eraser[i] = ( s[0][i] - 'A' + l[1] ) ) ) % mo[k] ;
}
if( hs[0][0]==hs[1][0] && hs[0][1]==hs[1][1] && hs[0][2]==hs[1][2] ) ans ++ ;
}
printf("%d\n",ans ) ;
}
}
DebugLog
带取模的哈希值用 unsigned long long 存 ,溢出会错