题解:CF291E Tree-String Problem

题意

给定一棵树,树的边上有字符串,字符串可以按照由父亲到儿子的方向拼接,求模式串 \(t\) 出现的次数。

思路

直接使用哈希。提前预处理出模式串 \(t\) 对应的哈希值,在搜索时计算当前点到儿子之间的边上的字符串对应的哈希值,并将其加入数组中,这样我们就得到了根节点到当前节点之间所有边上字符串拼接起来得到的长串的哈希值。计算答案的时候为了避免重复计算,只需要统计新加入的这一段(当前节点到儿子)上的每个字母为终点是否可以匹配。在回溯时记得更新长串的长度,减掉新加的字符串。

代码

#include<bits/stdc++.h>
#define int unsigned long long
#define MAXN 1000005
#define base 1331
using namespace std;
const int inf=1e18;
int n,m,cnt,head[MAXN],has[MAXN],len,hs,ans,p[MAXN];
string t;
struct Edge{
	int value,next;
	string s;
}edge[MAXN];
void addedge(int u,int v,string st){
	edge[++cnt].value=v;
	edge[cnt].next=head[u];
	edge[cnt].s=st;
	head[u]=cnt;
}
int fhas(int l,int r){
	return has[r]-has[l-1]*p[r-l+1];
}
void dfs(int x){
	for(int i=head[x];i;i=edge[i].next){
		int y=edge[i].value;
		string st=edge[i].s;
		for(int j=0;j<st.size();j++)has[len+j+1]=has[len+j]*base+st[j];
		for(int j=0;j<st.size();j++){
			if(len+j+1>=m){
				if(fhas(len+j-m+2,len+j+1)==hs)ans++;
			}
		}
		len+=st.size();
		dfs(y);
		len-=st.size();
	}
}
signed main(){
	p[0]=1;
	for(int i=1;i<=MAXN-5;i++)p[i]=p[i-1]*base;
	scanf("%lld",&n);
	for(int i=2;i<=n;i++){
		int x;string st;
		cin>>x>>st;
		addedge(x,i,st);
	}
	cin>>t;m=t.size();
	for(int i=1;i<=m;i++){
		has[i]=has[i-1]*base+t[i-1];
	}
	hs=has[m];
	dfs(1);
	printf("%lld\n",ans);
	return 0;
}

AC 记录

posted @ 2025-11-02 22:14  CharlieCai2024  阅读(26)  评论(0)    收藏  举报