P14363 [CSP-S 2025] 谐音替换 / replace
明明都写出 AC 自动机了,为什么要否定自己呢?
因为只能换一次,所以如果一个串可以那么它的位置是固定的。我们观察 \(s_1,s_2\) 不同的位置,发现从最左到最右需要构成一个连续子区间,那么如果可以和 \(t_1,t_2\) 匹配就要求 \(t\) 的同样的连续最大子区间需要与 \(s\) 的相同。那么我们考虑先用哈希分一下不同的情况,之后就只需要判断有几个 \(s_1\) 和 \(t_1\) 能够在这个位置匹配。需要将这两个连续最大子区间都换成一个特殊字符,之后放到 AC 自动机上构成一个 trie 森林,之后就跑一个 AC 自动机然后回溯一下就做完了。但是注意分段的需要写一个哈希 map,否则直接用 map<string> 显然会 TLE。复杂度\(O(L_1+L_2)\)。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
using namespace std;
typedef long long ll;
const int MAXL=5e6+5;
const int MAXN=2e5+5;
const ll MOD1=998244353;
const ll MOD2=1e9+7;
struct node{
int c[28],fail,ed;
}t[MAXL];
int tot;
int loc[MAXN];
int tptot;
map<pair<pair<ll,ll>,pair<ll,ll>>,int>tn;
int L[MAXN],R[MAXN];
int gl,gr;
pair<ll,ll>ghsh(string p){
ll val1=0,val2=0;
for(auto c:p){
val1=val1*26%MOD1+c-'a';
val2=val2*26%MOD2+c-'a';
val1%=MOD1,val2%=MOD2;
}
return {val1,val2};
}
pair<pair<ll,ll>,pair<ll,ll>>hsh(string p,string q){
return {ghsh(p),ghsh(q)};
}
int gid(string p,string q,bool ad){
int l=-1,r=-2;
string sl="",sr="";
rep(j,0,int(p.size())-1){
if(p[j]!=q[j]){
l=r=j;
rep(k,j,int(p.size())-1){
if(p[k]!=q[k]){
r=k;
}
};
break;
}
};
rep(j,l,r){
sl+=p[j],sr+=q[j];
};
gl=l,gr=r;
pair<pair<ll,ll>,pair<ll,ll>>sh=hsh(sl,sr);
if(!tn.count(sh)){
if(ad){
tn[sh]=++tptot;
}else{
return -1;
}
}
return tn[sh];
}
int n,m;
string sa[MAXN],sb[MAXN];
void insert(int x){
int u=loc[x];
string ls="rt";
for(auto c:sa[x]){
int v;
if(c=='#'){
v=26;
}else{
v=c-'a';
}
if(!t[u].c[v]){
t[u].c[v]=++tot;
// cout<<"("<<ls<<")"<<u<<" ("<<c<<")"<<tot<<"\n";
}
ls=c;
u=t[u].c[v];
}
t[u].ed++;
}
void build(){
queue<int>q;
rep(i,1,tptot){
t[i].fail=i;
rep(j,0,26){
if(t[i].c[j]){
t[t[i].c[j]].fail=i;
q.push(t[i].c[j]);
}else{
t[i].c[j]=i;
}
}
}
while(!q.empty()){
int u=q.front();
q.pop();
// cout<<u<<" "<<t[u].fail<<"\n";
rep(i,0,26){
int v=t[u].c[i];
if(v){
t[v].fail=t[t[u].fail].c[i];
q.push(v);
}else{
t[u].c[i]=t[t[u].fail].c[i];
}
}
}
}
int query(string s,int x){
int u=x,ans=0;
stack<pair<int,int>>sta;
for(auto c:s){
int v;
if(c=='#'){
v=26;
}else{
v=c-'a';
}
// cout<<c<<" "<<v<<" "<<u<<"\n";
u=t[u].c[v];
for(int i=u;t[i].ed!=-1;i=t[i].fail){
// cout<<i<<" "<<t[i].ed<<"\n";
ans+=t[i].ed;
sta.push({i,t[i].ed});
t[i].ed=-1;
}
}
while(!sta.empty()){
t[sta.top().first].ed=sta.top().second;
sta.pop();
}
return ans;
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n>>m;
rep(i,1,n){
cin>>sa[i]>>sb[i];
loc[i]=gid(sa[i],sb[i],true);
L[i]=gl,R[i]=gr;
};
tot=tptot;
rep(i,1,n){
rep(j,L[i],R[i]){
sa[i][j]='#';
}
// cout<<sa[i]<<" "<<loc[i]<<"\n";
insert(i);
}
build();
// rep(i,1,tot){
// cout<<i<<" "<<t[i].fail<<"\n";
// }
rep(i,1,m){
string s,t;
cin>>s>>t;
if(s.size()!=t.size()){
cout<<0<<"\n";
continue;
}
int nm=gid(s,t,false);
if(nm==-1){
cout<<0<<"\n";
continue;
}
rep(j,gl,gr){
s[j]='#';
}
// cout<<s<<" "<<nm<<"\n";
cout<<query(s,nm)<<"\n";
}
return 0;
}

浙公网安备 33010602011771号