BZOJ4598: [Sdoi2016]模式字符串(点分治 hash)
题意
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)的更多相关文章
- 【BZOJ4598】[Sdoi2016]模式字符串 树分治+hash
[BZOJ4598][Sdoi2016]模式字符串 Description 给出n个结点的树结构T,其中每一个结点上有一个字符,这里我们所说的字符只考虑大写字母A到Z,再给出长度为m的模式串s,其中每 ...
- BZOJ.4598.[SDOI2016]模式字符串(点分治 Hash)
LOJ BZOJ 洛谷 点分治.考虑如何计算过\(rt\)的答案. 记\(pre[i]\)表示(之前的)子树内循环匹配了\(S\)的前缀\(i\)的路径有多少,\(suf[i]\)表示(之前的)子树内 ...
- Bzoj4598: [Sdoi2016]模式字符串 点分治 哈希
国际惯例的题面:这种关于树上路径的题,我也没什么好办法,只好点分治.考虑当前分治重心为root,如何统计经过分治重心的路径的答案.我们令prf[i]表示某个点到root的路径(不含root)已经循环匹 ...
- BZOJ4598 [Sdoi2016]模式字符串 【点分治 + hash】
题目 给出n个结点的树结构T,其中每一个结点上有一个字符,这里我们所说的字符只考虑大写字母A到Z,再给出长度为m 的模式串s,其中每一位仍然是A到z的大写字母.Alice希望知道,有多少对结点< ...
- bzoj4598: [Sdoi2016]模式字符串
Description 给出n个结点的树结构T,其中每一个结点上有一个字符,这里我们所说的字符只考虑大写字母A到Z,再给出长度为m 的模式串s,其中每一位仍然是A到z的大写字母.Alice希望知道,有 ...
- P4075 [SDOI2016]模式字符串
总结 P4075 [SDOI2016]模式字符串 题目描述 给出n个结点的树结构T,其中每一个结点上有一个字符,这里我们所说的字符只考虑大写字母A到Z,再给出长度为m的模式串s,其中每一位仍然是A到z ...
- [SDOI2016] 模式字符串 (BZOJ4598 & VIJOS1995)
首先直接点分+hash就可以做,每个点用hash判断是否为S重复若干次后的前缀或后缀,每个子树与之前的结果O(m)暴力合并.在子树大小<m时停止分治,则总复杂度为O(nlog(n/m)). 问题 ...
- bzoj 4598: [Sdoi2016]模式字符串
题目描述 给出n个结点的树结构T,其中每一个结点上有一个字符,这里我们所说的字符只考虑大写字母A到Z,再给出长度为m的模式串s,其中每一位仍然是A到z的大写字母. Alice希望知道,有多少对结点&l ...
- [SDOI2016]模式字符串
Description 给出n个结点的树结构T,其中每一个结点上有一个字符,这里我们所说的字符只考虑大写字母A到Z,再给出长度为m的模式串s,其中每一位仍然是A到z的大写字母.Alice希望知道,有多 ...
随机推荐
- Spring注解学习笔记一
一.Retention注解Retention(保留)注解说明,这种类型的注解会被保留到那个阶段. 有三个值: 1.RetentionPolicy.SOURCE —— 这种类型的Annotations只 ...
- 数学规划求解器lp_solve超详细教程
前言 最近小编学了运筹学中的单纯形法.于是,很快便按奈不住跳动的心.这不得不让我拿起纸和笔思考着,一个至关重要的问题:如何用单纯形法装一个完备的13? 恰巧,在我坐在图书馆陷入沉思的时候,一位漂亮的小 ...
- Linux运维: Rsync同步数据(ubuntu16.04+windows10)
rsync同步数据 -环境:Linux (ubuntu16.04) + windows10 Linux: 安装 sudo apt-get install rsync rsync --version 查 ...
- 2016级算法期末上机-E.中等·ModricWang's Fight with DDLs II
1125 ModricWang's Fight with DDLs II 思路 圆内被划分部分数的计算方式如下: 圆内部的每一个交点都使得总份数增加了一:除此之外,每一根直线段最后抵达圆周时,总份数也 ...
- jenkins+appium android app自动化测试
jenkins安装 pytest+jenkins安装+allure报告 新建任务 其他默认,保存 立即构建 test_login.py from src.pages import login_page ...
- mfix中输出DEM颗粒的固相速度到网格
基于mfix-19.1.2版本 方法一:直接输出差值网格固相速度 注:这种方式只适用于garg 2012颗粒差值格式在DEM中,默认是无法输出固相速度的网格值的: 但是通过搜索des文件夹下V_s关键 ...
- (转)MySQL主主互备结合keepalived实现高可用
MySQL主主互备结合keepalived实现高可用 原文:http://7424593.blog.51cto.com/7414593/1741717 试验环境: master:192.168.1.2 ...
- WPF UpdateSourceTrigger属性
TextBox中的变化并不是立即传递到源,而是在TextBox失去焦点后,源才更新.这种表现由绑定中的UpdateSourceTrigger属性来控制.它的默认值是Default,源会根据你绑定的属性 ...
- 【LeetCode题解】20_有效的括号(Valid-Parentheses)
目录 20_有效的括号(Valid-Parentheses) 描述 解法 思路 Java 实现 Python 实现 复杂度分析 20_有效的括号(Valid-Parentheses) 描述 给定一个只 ...
- Jquery 搜索框自动提示
为文本框增加自动提示下拉功能,比如输入 1,则从后台数据库查询出包含1 的字段,在文本框增加下拉列表供用户选择 ajax 返回数据为搜索查询字段的json集合 <script src=" ...