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希望知道,有多 ...
随机推荐
- 使用 Hexo + github 搭建个人博客
来自:http://www.cnblogs.com/fengzheng/p/8031518.html Hexo 是什么 Hexo 是一个快速.简洁且高效的博客框架.Hexo 使用 Markdown(或 ...
- css中代码格式以及@import的语法结构
CSS中代码格式 CSS是Cascading Style Sheets(层叠样式表)的缩写.是一种对web文档添加样式的简单机制,属于表现层的布局语言. 1.基本语法规范分析一个典型CSS的语句: p ...
- jquery插件制作,下拉菜单
要求输入框点击出现下拉菜单,并实现以下功能: 1.首先点击地点标签页,选择好地点: 2.自动显示相应节点标签页显示节点信息,选择好节点 3.自动显示相应的连接点,选择连接点,连接点被选中并被传送的输入 ...
- 实验一 c++简单程序设计
一.实验内容 1.ex 2_28 (1) 用if...else判断 #include<iostream> using namespace std; int main() { char i; ...
- JAVA编程思想第一章——对象导论
- c#Task类。实现异步的一种方式
Task和Task<TResult>是c#提供的一种实现异步功能的2个类.Task<TResult>继承Task类,有返回参数. 1.基本用法 不嵌套利用静态方法创建和运行任务 ...
- 布局优化之ViewStub、Include、merge使用分析
布局技巧 在Android开发过程中,我们会遇到很多的问题,随着UI界面越来越多,布局的重复性.复杂度也随之增加,所幸的是,Android官方也给出了几个对布局进行优化的方法,下面根据自己的理解对官方 ...
- [Xamarin.Android]如何引用JAR檔案 (转帖)
這個範例是如何在Xamarin.Android中去使用一個我們自行在開發的JAR檔案. 主要會執行的步驟如下 1. 在Xamarin建立一個Android Java Bindings Library ...
- android逆向基础:apk 反编译 重打包 重签名
apk 反编译大家都比较熟悉,这里只做一个笔记. 1 反编译 apk apktool d perfect.apk 这样就把资源文件解压缩了, classes.dex 也反编译成了 smali 文件 2 ...
- 对于maven创建spark项目的pom.xml配置文件(图文详解)
不多说,直接上干货! http://mvnrepository.com/ 这里,怎么创建,见 Spark编程环境搭建(基于Intellij IDEA的Ultimate版本)(包含Java和Scala版 ...