LOJ

BZOJ

洛谷


点分治。考虑如何计算过\(rt\)的答案。

记\(pre[i]\)表示(之前的)子树内循环匹配了\(S\)的前缀\(i\)的路径有多少,\(suf[i]\)表示(之前的)子树内循环匹配了\(S\)的后缀\(i\)的路径有多少。

一个点如果能作为前缀\(dep\%m\)出现,然后\(s[rt]=s[dep\%m+1]\),就可以统计\(suf[m-dep\%m-1]\)的贡献。

作为后缀出现同理。

判某个深度\(dep\)是否是循环匹配了\(S\)的前缀\(i\),本来想的是首先\(dep\sim dep-m+1\)匹配了整个\(S\),其次再判\(dep-m\)匹配了前缀\(i\)。其实只要先把\(S\)变成长度为\(n\)的循环串,再对它求\(Hash\)就可以惹。这样每次插入一个字符时在字符串开头插入,只需要判断\(hs_{now}==hs[dep]\)。

判后缀就对应一下那个\(hs_{now}\)好了(每次在开头插入字符),即若出现了\(s[n-2],s[n-1],s[n]\),得到的Hash值是\(s[n],s[n-1],s[n-2]\)的,所以把串反过来求Hash值,判一下\(hs_{now}==hs'[dep]\)就好啦。

复杂度\(O(n\log n)\),这个数据范围应该卡不掉的叭?(应该。但是实际数据范围小惹?)

初始化\(1e6\)的\(pow\)数组还不如每次初始化\(n\)的=-=

另外单组数据是\(3\leq n,m\leq 1e5\)的。


//9940kb	2808ms
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define seed 31
#define gc() getchar()
#define MAXIN 500000
//#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
typedef unsigned long long ull;
const int N=1e5+5; int m,s[N],ch[N],Enum,H[N],nxt[N<<1],to[N<<1],Min,root,sz[N],pre[N],suf[N],spre[N],ssuf[N],Maxd;
LL Ans;
ull pw[N],hs[N],hs2[N];
bool vis[N];
char IN[MAXIN],*SS=IN,*TT=IN; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
return now;
}
inline void AE(int u,int v)
{
to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
}
inline void GetHash(ull *a,int *s,int n,int m)
{
for(int i=m+1; i<=n; ++i) s[i]=s[i-m];
for(int i=1; i<=n; ++i) a[i]=a[i-1]*seed+s[i];
}
void FindRoot(int x,int fa,int tot)
{
int mx=0; sz[x]=1;
for(int i=H[x],v; i; i=nxt[i])
if(!vis[v=to[i]]&&v!=fa)
FindRoot(v,x,tot), sz[x]+=sz[v], sz[v]>mx&&(mx=sz[v]);
mx=std::max(mx,tot-mx);
if(mx<Min) Min=mx, root=x;
}
void DFS(int x,int fa,int dep,ull val,const int Chrt)
{
Maxd=std::max(Maxd,dep), val+=pw[dep-1]*ch[x];
int tmp=dep%m;
if(val==hs[dep]) ++pre[tmp], s[tmp+1]==Chrt&&(Ans+=ssuf[m-tmp-1]);
if(val==hs2[dep]) ++suf[tmp], s[m-tmp]==Chrt&&(Ans+=spre[m-tmp-1]);
for(int i=H[x],v; i; i=nxt[i])
if(!vis[v=to[i]]&&v!=fa) DFS(v,x,dep+1,val,Chrt);
}
void Solve(int x)
{
vis[x]=1; int mx=0; spre[0]=ssuf[0]=1;
// spre[0]=ch[x]==s[1], ssuf[0]=ch[x]==s[m];//这个不需要判的叭。因为统计贡献时要求s[p]=ch[rt]。
for(int i=H[x],v; i; i=nxt[i])
if(!vis[v=to[i]])
{
Maxd=0, DFS(v,x,1,0,ch[x]), Maxd=std::min(Maxd,m-1), mx=std::max(mx,Maxd);
for(int j=0,tmp=Maxd; j<=tmp; ++j) spre[j]+=pre[j], ssuf[j]+=suf[j], pre[j]=suf[j]=0;
}
for(int i=0; i<=mx; ++i) spre[i]=ssuf[i]=0;
for(int i=H[x],v; i; i=nxt[i])
if(!vis[v=to[i]]) Min=N, FindRoot(v,x,sz[v]), Solve(root);
} int main()
{
pw[0]=1;
for(int T=read(),mx=0; T--; )
{
int n=read(),m=read(); ::m=m;
Enum=0, memset(H,0,n+1<<2), memset(vis,0,n+1);
if(mx<n)
{
for(int i=mx+1; i<=n; ++i) pw[i]=pw[i-1]*seed;
mx=n;
}
register char c; while(!isalpha(c=gc())); ch[1]=c-65+1;
for(int i=2; i<=n; ++i) ch[i]=gc()-65+1;
for(int i=1; i<n; ++i) AE(read(),read());
while(!isalpha(c=gc())); s[1]=c-65+1;
for(int i=2; i<=m; ++i) s[i]=gc()-65+1;
GetHash(hs,s,n,m), std::reverse(s+1,s+1+m), GetHash(hs2,s,n,m), std::reverse(s+1,s+1+m);
Ans=0, Min=N, FindRoot(1,1,n), Solve(root), printf("%lld\n",Ans);
} return 0;
}

BZOJ.4598.[SDOI2016]模式字符串(点分治 Hash)的更多相关文章

  1. 【BZOJ4598】[Sdoi2016]模式字符串 树分治+hash

    [BZOJ4598][Sdoi2016]模式字符串 Description 给出n个结点的树结构T,其中每一个结点上有一个字符,这里我们所说的字符只考虑大写字母A到Z,再给出长度为m的模式串s,其中每 ...

  2. BZOJ4598: [Sdoi2016]模式字符串(点分治 hash)

    题意 题目链接 Sol 直接考虑点分治+hash匹配 设\(up[i]\)表示\(dep \% M = i\)的从下往上恰好与前\(i\)位匹配的个数 \(down\)表示\(dep \% M = i ...

  3. bzoj 4598: [Sdoi2016]模式字符串

    题目描述 给出n个结点的树结构T,其中每一个结点上有一个字符,这里我们所说的字符只考虑大写字母A到Z,再给出长度为m的模式串s,其中每一位仍然是A到z的大写字母. Alice希望知道,有多少对结点&l ...

  4. Bzoj4598: [Sdoi2016]模式字符串 点分治 哈希

    国际惯例的题面:这种关于树上路径的题,我也没什么好办法,只好点分治.考虑当前分治重心为root,如何统计经过分治重心的路径的答案.我们令prf[i]表示某个点到root的路径(不含root)已经循环匹 ...

  5. P4075 [SDOI2016]模式字符串

    总结 P4075 [SDOI2016]模式字符串 题目描述 给出n个结点的树结构T,其中每一个结点上有一个字符,这里我们所说的字符只考虑大写字母A到Z,再给出长度为m的模式串s,其中每一位仍然是A到z ...

  6. BZOJ4598 [Sdoi2016]模式字符串 【点分治 + hash】

    题目 给出n个结点的树结构T,其中每一个结点上有一个字符,这里我们所说的字符只考虑大写字母A到Z,再给出长度为m 的模式串s,其中每一位仍然是A到z的大写字母.Alice希望知道,有多少对结点< ...

  7. bzoj4598: [Sdoi2016]模式字符串

    Description 给出n个结点的树结构T,其中每一个结点上有一个字符,这里我们所说的字符只考虑大写字母A到Z,再给出长度为m 的模式串s,其中每一位仍然是A到z的大写字母.Alice希望知道,有 ...

  8. [SDOI2016]模式字符串

    Description 给出n个结点的树结构T,其中每一个结点上有一个字符,这里我们所说的字符只考虑大写字母A到Z,再给出长度为m的模式串s,其中每一位仍然是A到z的大写字母.Alice希望知道,有多 ...

  9. [SDOI2016] 模式字符串 (BZOJ4598 & VIJOS1995)

    首先直接点分+hash就可以做,每个点用hash判断是否为S重复若干次后的前缀或后缀,每个子树与之前的结果O(m)暴力合并.在子树大小<m时停止分治,则总复杂度为O(nlog(n/m)). 问题 ...

随机推荐

  1. 自古枪兵幸运E

    好梗 求方程的解.n个可以奇数可以偶数,m个必须是偶数 两种方法: 都是O(nlogn)logn是LUCAS定理 法一: 有奇数有偶数,如果都是偶数,那么可以直接除以二然后组合数学 所以枚举有几个奇数 ...

  2. 51nod1812树的双直径(换根树DP)

    传送门:http://www.51nod.com/Challenge/Problem.html#!#problemId=1812 题解:头一次写换根树DP. 求两条不相交的直径乘积最大,所以可以这样考 ...

  3. 我眼中的支持向量机(SVM)

    看吴恩达支持向量机的学习视频,看了好几遍,才有一点的理解,梳理一下相关知识. (1)优化目标: 支持向量机也是属于监督学习算法,先从优化目标开始.   优化目标是从Logistics regressi ...

  4. MySQL_表锁_lock tables tableName read

    pre.环境准备 1.建立两个表S,T,并插入一些数据 --创建表S create table S(d int) engine=innodb; ); --创建表T create table T(c i ...

  5. saltstack主机管理项目:主机管理项目需求分析(一)

    1.场景: 我现在又一台裸机要实现一下任务 2.配置管理: 1.装上nginx,mysql 2.nginx用我指定的配置文件 3.mysql用户 4.设置一个默认的数据库访问权限 5.启动mysql ...

  6. Error creating bean with name

    最近在学一个东西,要使用SSM新建一个案例,是这样滴,我有如下 DeptDAO DeptService DeptServiceImpl DeptController Dept Mybatis 首先,我 ...

  7. 解决Java getResource 路径中含有中文的情况

    问题描述 当Java调用getResource方法,但是因为路径中含有中文时,得不到正确的路径 问题分析 编码转换问题 当我们使用ClassLoader的getResource方法获取路径时,获取到的 ...

  8. 适配器模式-Adapter(Java实现)

    适配器模式-Adapter 是作为两个不兼容的接口之间的桥梁. 本篇文章的代码github地址: https://github.com/GoldArowana/design-patterns/tree ...

  9. wxpython多线程间通信

    #!bin/bash/python # -*- coding=utf-8 -*- import time import wx from threading import Thread from wx. ...

  10. [物理学与PDEs]第1章第7节 媒质中的 Maxwell 方程组 7.1 媒质中的 Maxwell 方程组

    1.媒质的极化 (1) 束缚电荷: 被束缚在原来位置上的电荷. (2) 在电磁场中, 束缚电荷会有一微小的运动, 而产生电偶极矩. 此即称为媒质的极化. (3) 设电极化强度 (单位体积的电偶极矩) ...