题意

题目链接

Sol

直接考虑点分治+hash匹配

设\(up[i]\)表示\(dep \% M = i\)的从下往上恰好与前\(i\)位匹配的个数

\(down\)表示\(dep \% M = i\)的从上往下恰好与后\(i\)位匹配的个数

暴力转移即可

复杂度:\(O(nlog^2n)??\)

代码写起来有一车边界

#include<bits/stdc++.h>
#define ull unsigned long long
#define LL long long
#define int long long
#define siz(v) ((int)v.size())
using namespace std;
const int MAXN = 1e6 + 10, INF = 1e10 + 10;
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int N, M, Root, siz[MAXN], mx[MAXN], Siz, dep[MAXN], up[MAXN], down[MAXN], su[MAXN], sd[MAXN];
LL ans;
bool det[MAXN];
char a[MAXN], b[MAXN];
vector<int> v[MAXN];
ull hs[MAXN], hp[MAXN], po[MAXN], base = 1331;
map<ull, bool> mp;
void FindRoot(int x, int fa) {
siz[x] = 1; mx[x] = 0;
for(int i = 0; i < siz(v[x]); i++) {
int to = v[x][i];
if(to == fa || det[to]) continue;
FindRoot(to, x);
siz[x] += siz[to]; mx[x] = max(mx[x], siz[to]);
}
mx[x] = max(mx[x], Siz - siz[x]);
if(mx[x] < mx[Root]) Root = x;
}
int dfs(int x, int fa, ull now) {
siz[x] = 1;
dep[x] = dep[fa] + 1;
now = now * base + a[x];
if(hp[dep[x]] == now) up[(dep[x] - 1) % M + 1]++, ans += sd[M - (dep[x] - 1) % M];
if(hs[dep[x]] == now) down[(dep[x] - 1) % M + 1]++, ans += su[M - (dep[x] - 1) % M];
// printf("%d %d\n", x, ans);
int td =1;
for(int i = 0; i < siz(v[x]); i++) {
int to = v[x][i];
if(to == fa || det[to]) continue;
td = max(td, dfs(to, x, now) + 1);
siz[x] += siz[to];
}
return td;
}
void work(int x) {
int tk = 0, tmp = 0;
det[x] = 1; dep[x] = 1; su[1] = sd[1] = 1;//tag;
for(int i = 0; i < siz(v[x]); i++) {
int to = v[x][i];
if(det[to]) continue;
tk = min(M, dfs(to, x, a[x]) + 1), tmp = max(tmp, tk);
for(int j = 1; j <= tk; j++) su[j] += up[j], sd[j] += down[j], up[j] = down[j] = 0;
}
for(int i = 1; i <= tmp; i++) su[i] = sd[i] = 0;
for(int i = 0; i < siz(v[x]); i++) {
int to = v[x][i];
if(to == x || det[to]) continue;
Siz = siz[to]; Root = 0; FindRoot(to, x);
work(Root);
}
}
void init() {
for(int i = 1; i <= N; i++) v[i].clear();
memset(det, 0, sizeof(det));
memset(siz, 0, sizeof(siz));
memset(mx, 0, sizeof(mx));
ans = 0;
}
void solve() { N = read(); M = read();
init();
scanf("%s", a + 1);
for(int i = 1; i <= N - 1; i++) {
int x = read(), y = read();
v[x].push_back(y); v[y].push_back(x);
}
for(int i = 1; i <= N; i++) reverse(v[i].begin(), v[i].end());
scanf("%s", b + 1); po[0] = 1;
for(int i = 1; i <= N; i++) {
hp[i] = hp[i - 1] + b[(i - 1) % M + 1] * po[i - 1];
hs[i] = hs[i - 1] + b[M - (i - 1) % M] * po[i - 1];
po[i] = base * po[i - 1];
}
Siz = N; mx[0] = INF; Root = 0; FindRoot(1, 0);
work(1);
printf("%d\n", ans);
}
signed main() {
freopen("a.in", "r", stdin);
for(int T = read(); T; T--, solve());
return 0;
}

BZOJ4598: [Sdoi2016]模式字符串(点分治 hash)的更多相关文章

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

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

  2. BZOJ.4598.[SDOI2016]模式字符串(点分治 Hash)

    LOJ BZOJ 洛谷 点分治.考虑如何计算过\(rt\)的答案. 记\(pre[i]\)表示(之前的)子树内循环匹配了\(S\)的前缀\(i\)的路径有多少,\(suf[i]\)表示(之前的)子树内 ...

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

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

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

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

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

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

  6. P4075 [SDOI2016]模式字符串

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

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

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

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

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

  9. [SDOI2016]模式字符串

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

随机推荐

  1. python基础知识梳理----3基本数据类型,int,bool,str ,for 循环,迭代

    一:python的基本类型 1.int  -----整数,主要进行数学运算 2.str  -----字符串,可以保存少量数据,并进行相关操作, 3. bool ---布尔类型,判断真假 4.list ...

  2. C#-WebForm-AJAX阿贾克斯(二)★★★★★ajax的完整结构★★★★★

    ajax完整结构: $.ajax({ url:"",//服务器路径 data:{},//给服务端传递的参数,可以没有,也可以是多个 type:"post", / ...

  3. C 语言调试信息输出宏定义

    C 语言经常在实际的调试过程中,使用最基本的调试方法printf,我们可以使用__FILENAME__.__FUNCTION__.__LINE__,增加自己的输出宏定义: #define DVR_PR ...

  4. CentOS7.6下模拟iSCSI,Windows来连

    如题,在CentOS7上模拟一个iSCSI设备,然后在Windows Server 2008上连接这个iSCSI设备 第一步,CentOS7上的操作.CentOS7上安装iSCSI模拟器需要3个包,我 ...

  5. [转] Elasticsearch 6.1官方入门教程

    一篇比较简要又全面的elasticsearch教程. https://blog.csdn.net/hololens/article/details/78932628

  6. 牛客OI周赛8-提高组A-用水填坑

    牛客OI周赛8-提高组A-用水填坑 题目 链接: https://ac.nowcoder.com/acm/contest/403/A 来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制: ...

  7. js 数组随机排序

    仅用于个人学习记录 javascript 数组随机排序1.最简洁的方法:function randomsort(a, b) {    return Math.random()>.5 ? -1 : ...

  8. php 如何截取中文字符串

    在网站应用中时常需要对相应的字符串进行截取.最常用的是使用substr函数对字符串进行截取. 然而,substr和strlen函数只在处理英文字符串时可以正确使用,在截取中文字符时,时常出现乱码.这时 ...

  9. Java简单聊天室

    实现Java简单的聊天室 所用主要知识:多线程+网络编程 效果如下图 /** * * @author Administrator * * 简单的多人聊天系统——重点:同时性,异步性 * 1.客户端:发 ...

  10. 老司机谈APK瘦身套路-图片资源篇

    APK作为Android系统安装包的文件格式,一直备受广大用户的关注,APK越是臃肿肥大,在下载安装过程中,它们耗费的流量会越多,安装等待时间也会越长:对于产品本身,意味着下载转化率会越低(因为竞品中 ...