传送门
题意:
给定一个母串和一个模式串,求匹配位置数。
其中小写字母可以作置换。
思路:
大写字母不动。
考虑如何变化小写字母。
假设当前是第
i
i
i为是
a
a
a,上一个
a
a
a在
j
j
j,我们把第
i
i
i位变成
i
−
j
i-j
i−j。
这样跑
k
m
p
kmp
kmp貌似挺有道理的。
然后每次匹配的时候每个小写字母第一次出现时要特判。
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
inline int Read(char*s){
int top=0;
char ch=gc();
while(!isalpha(ch))ch=gc();
while(isalpha(ch))s[++top]=ch,ch=gc();
return top;
}
const int N=1e6+5;
char s[N],t[N];
int n,m,a[N],b[N],las[N],fail[N];
inline bool check(int x,int y,int lim){return x==y||x>lim&&y>lim;}
int main(){
for(ri tt=read();tt;--tt){
n=Read(s);
m=Read(t);
for(ri i=0;i<26;++i)las[i]=0;
for(ri i=1;i<=n;++i){
if(s[i]>='A'&&s[i]<='Z')a[i]=-s[i];
else{
a[i]=i-las[s[i]-'a'];
las[s[i]-'a']=i;
}
}
for(ri i=0;i<26;++i)las[i]=0;
for(ri i=1;i<=m;++i){
if(t[i]>='A'&&t[i]<='Z')b[i]=-t[i];
else{
b[i]=i-las[t[i]-'a'];
las[t[i]-'a']=i;
}
}
for(ri i=1,j=0;i<m;++i){
while(j&&!check(b[j+1],b[i+1],j))j=fail[j];
fail[i+1]=check(b[j+1],b[i+1],j)?++j:0;
}
int ans=0;
for(ri i=0,j=0;i<n;++i){
while(j&&!check(b[j+1],a[i+1],j))j=fail[j];
if(check(b[j+1],a[i+1],j))++j;
if(j==m)++ans,j=fail[j];
}
cout<<ans<<'\n';
}
return 0;
}