列表

详情


NC20387. [SDOI2016]模式字符串

描述

给出n个结点的树结构T,其中每一个结点上有一个字符,这里我们所说的字符只考虑大写字母A到Z,再给出长度为m的模式串s,其中每一位仍然是A到z的大写字母。
Alice希望知道,有多少对结点 < u,v > 满足T上从u到V的最短路径形成的字符串可以由模式串S重复若干次得到?
这里结点对 < u,v > 是有序的,也就是说 < u,v > 和 < v,u > 需要被区分. 
所谓模式串的重复,是将若干个模式串S依次相接(不能重叠).例如当S=PLUS的时候,重复两次会得到PLUSPLUS, 重复三次会得到PLUSPLUSPLUS,同时要注恿,重复必须是整数次的。例如当S=XYXY时,因为必须重复整数次,所以XYXYXY不能看作是S重复若干次得到的。

输入描述

每一个数据有多组测试,第一行输入一个整数C,表示总的测试个数。
对于每一组测试来说: 第一行输入两个整数,分别表示树T的结点个数n与模式长度m。结点被依次编号为1到n,之后一行,依次给出了n个大写字母(以一个长度为n的字符串的形式给出),依次对应树上每一个结点上的字符(第i个字符对应了第i个结点).
之后n-1行,每行有两个整数u和v表示树上的一条无向边,之后一行给定一个长度为m的由大写字母组成的字符串,为模式串S。
1 ≤ C ≤ 10,3 ≤ N ≤ 10000003 ≤ M ≤ 1000000

输出描述

给出C行,对应C组测试。每一行输出一个整数,表示有多少对节点 < u,v > 满足从u到v的路径形成的字符串恰好是模式串的若干次重复.

示例1

输入:

1
11 4
IODSSDSOIOI
1 2
2 3
3 4
1 5
5 6
6 7
3 8
8 9
6 10
10 11
SDOI

输出:

5

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 984ms, 内存消耗: 20088K, 提交时间: 2019-03-09 15:05:14

#include<bits/stdc++.h>
#define debug(x) cout<<#x<<"="<<x<<endl
typedef unsigned long long ll;
using namespace std;
const int maxn = 1000009;
const int p = 31;
 
int first[maxn];
struct edg
{
	int next;
	int to;
}e[maxn<<1];
int e_sum;
ll mid;
int n,m,T,rt,sum,mx;
char str[maxn],temp[maxn];
ll ft[maxn],val[maxn],h1[maxn],h2[maxn];
int W[maxn],siz[maxn],cnt1[maxn],cnt2[maxn];
bool vis[maxn];
long long ans;
 
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void add_edg(int x,int y)
{
	e_sum++;
	e[e_sum].next=first[x];
	first[x]=e_sum;
	e[e_sum].to=y;
}
 
void ClearLove()
{
	memset(vis,0,sizeof vis);memset(first,0,sizeof first);
	e_sum=0;ans=0;
}
 
void find(int x,int f)
{
	W[x]=0;siz[x]=1;
	for(int i=first[x];i;i=e[i].next)
	{
		int w=e[i].to;
		if(vis[w]||w==f) continue;
		find(w,x);
		siz[x]+=siz[w];
		W[x]=max(W[x],siz[w]);
	}W[x]=max(W[x],sum-siz[x]);
	if(W[x]<W[rt]) rt=x;
}
void dfs(int x,int f,int step,ll now)
{
	if(now==h1[step]&&mid==temp[step%m+1]-'A'+1) ans+=cnt2[m-step%m-1]; // could be the head of ans =w=
	if(now==h2[step]&&mid==temp[m-step%m]-'A'+1) ans+=cnt1[m-step%m-1]; // could be the tail of ans =w=
	for(int i=first[x];i;i=e[i].next)
	{
		int w=e[i].to;
		if(w==f||vis[w]) continue;
		dfs(w,x,step+1,now+val[w]*ft[step]);
	}mx=max(mx,step);
}
void update(int x,int f,int step,ll now)
{
	if(now==h1[step]) cnt1[step%m]++;
	if(now==h2[step]) cnt2[step%m]++;
	for(int i=first[x];i;i=e[i].next)
	{
		int w=e[i].to;
		if(w==f||vis[w]) continue;
		update(w,x,step+1,now+val[w]*ft[step]);
	}
}
void solve(int x)
{
	vis[x]=1;mid=val[x];mx=0;
	cnt1[0]=cnt2[0]=1;
	if(m==1&&val[x]==h1[m]) ans++;
	for(int i=first[x];i;i=e[i].next)
	{
		int w=e[i].to;
		if(vis[w]) continue;
		dfs(w,x,1,val[w]);
		update(w,x,1,val[w]);
	}
	for(int i=0;i<=min(m,mx);i++) cnt1[i]=cnt2[i]=0;
	for(int i=first[x];i;i=e[i].next)
	{
		int w=e[i].to;
		if(vis[w]) continue;
		sum=siz[w];rt=0;
		find(w,0);solve(rt);
	}
}
 
int main()
{
	T=read();
	ft[0]=1;for(int i=1;i<=maxn-9;i++) ft[i]=ft[i-1]*p;
	while(T--)
	{
		ClearLove();
		n=read();m=read();
		scanf("%s",str+1);
		for(int i=1;i<=n;i++) val[i]=str[i]-'A'+1;
		for(int i=1;i<n;i++)
		{
			int x=read(),y=read();
			add_edg(x,y);add_edg(y,x);
		}
		scanf("%s",str+1);memcpy(temp,str,sizeof temp);
		for(int i=m+1;i<=n;i++) str[i]=str[i-m];
		for(int i=1;i<=n;i++) h1[i]=h1[i-1]*p+str[i]-'A'+1;reverse(str+1,str+1+m);
		for(int i=m+1;i<=n;i++) str[i]=str[i-m];
		for(int i=1;i<=n;i++) h2[i]=h2[i-1]*p+str[i]-'A'+1;
		sum=n;rt=0;W[0]=n+1;
		find(1,0);solve(rt);
		printf("%d\n",ans);
	}
	return 0;
}

上一题