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;
}
posted @ 2025-11-07 19:37  tanghg  阅读(50)  评论(0)    收藏  举报