P4075 [SDOI2016]模式字符串

题目

P4075 [SDOI2016]模式字符串

求树上两点对数量,满足其路径上结点的字符连接起来是串 (S) 可以循环得到的。

分析

首先这类树上统计点对,还有字符串的,通常,因为我们的点分治需要拼接,所有这样的题也一般是 点分治+字符串哈希 来完成。

这道题就是要拼接两个串,那么我们其实就可以用字符串哈希来拼接。

首先对于每一个串,如果它能成为我们循环串循环无穷次后的一个前缀/后缀,它才有可能拼接。

其次,我们可以把这一些串按照 (m) 个来划分,也就是模 (m) 意义下。

那么剩下的其实就是分别对于前缀和后缀进行模意义下的路径数个数,和P2634 [国家集训队]聪聪可可类似。

代码

#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
    x=0;char ch=getchar();bool f=false;
    while(!isdigit(ch)) f|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=f?-x:x;return;
}
template <typename T>
inline void write(T x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10^48);
	return;
}
#define ll long long
const int N=2e5+5,INF=1e9+7,MOD=1e9+7;
const ll base=31;
int n,m,k,t,Ans;
int head[N],to[N],nex[N],idx;
inline void add(int u,int v){
	nex[++idx]=head[u];
	to[idx]=v;
	head[u]=idx;
	return ;
}
char a[N],s[N];
ll pre[N],suf[N];
int PathCnt,siz[N],dep[N],FMax,Max,Root,Size;
int Sum[N][2],Num[N][2];
bool vis[N];
void GetRoot(int x,int fa){
	siz[x]=1;int Max=0;
	for(int i=head[x];i;i=nex[i]){
		int y=to[i];
		if(y==fa||vis[y]) continue;
		GetRoot(y,x);siz[x]+=siz[y];
		Max=max(Max,siz[y]);
	}
	Max=max(Max,Size-siz[x]);
	if(Max<FMax) FMax=Max,Root=x; 
	return ;
}
void GetPath(int x,ll Hash,int depth,int fa){
	Hash=(Hash*base+a[x]-'A')%MOD;
	dep[x]=depth;
	if(Hash==pre[depth]) Num[(depth-1)%m+1][0]++,Ans+=Sum[m-(depth-1)%m][1];
	if(Hash==suf[depth]) Num[(depth-1)%m+1][1]++,Ans+=Sum[m-(depth-1)%m][0];
	for(int i=head[x];i;i=nex[i]){
		int y=to[i];
		if(vis[y]||y==fa) continue;
		GetPath(y,Hash,depth+1,x);
		dep[x]=max(dep[x],dep[y]);
	}
	return ;
}
void DFS(int x){
	vis[x]=true;
	int len=0;
	Sum[1][0]=Sum[1][1]=1;
	for(int i=head[x];i;i=nex[i]){
		int y=to[i];
		if(vis[y]) continue;
		GetPath(y,a[x]-'A',2,x);
		int Maxdep=min(dep[y],m);len=max(len,Maxdep);
		for(int j=1;j<=Maxdep;j++) Sum[j][0]+=Num[j][0],Sum[j][1]+=Num[j][1],Num[j][0]=Num[j][1]=0;
	}
	for(int i=1;i<=len;i++) Sum[i][0]=Sum[i][1]=0;
	for(int i=head[x];i;i=nex[i]){
		int y=to[i];
		if(vis[y]) continue;
		Size=FMax=siz[y],Root=0,GetRoot(y,x),DFS(Root);
	}
	vis[x]=false;
	return ;
}
int main(){
	int t;
	read(t);
	while(t--){
		memset(head,0,sizeof(head));idx=Ans=0;
		read(n),read(m);
		scanf("%s",a+1);
		for(int i=1;i<n;i++){
			int u,v;
			read(u),read(v),add(u,v),add(v,u);
		}
		scanf("%s",s+1);
		ll tmp=1;
		for(int i=1;i<=n;i++){
			pre[i]=(pre[i-1]+tmp*(s[(i-1)%m+1]-'A')%MOD)%MOD;
			suf[i]=(suf[i-1]+tmp*(s[m-(i-1)%m]-'A')%MOD)%MOD;
			tmp=tmp*base%MOD;
		}
		Root=0,Size=FMax=n,GetRoot(1,0),DFS(Root);
		write(Ans),putchar('
');
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Akmaey/p/14726851.html