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希望知道,有多 ...
随机推荐
- the type initializer for 'system.drawingcore.gdiplus' threw an exception
Centos 7 yum install libgdiplus-devel reboot之后生效 apt install libgdiplus cp /usr/lib/libgdiplus.so ~/ ...
- gitlab的简单使用
mkdir folder //创建文件夹 cd folder/ git clone git连接 git status //git当前的状态 ls //当前目录下的所有文件 cd gitFolder 进 ...
- Docker 入门相关
什么是Docker和容器 可能是把Docker的概念讲的最清楚的一篇文章 为什么要用Docker 相关网址 Window平台Docker下载 一些基本知识 Volume docker volume l ...
- (转)如何在CentOS / RHEL 7上安装Elasticsearch,Logstash和Kibana(ELK)
原文:https://www.howtoing.com/install-elasticsearch-logstash-and-kibana-elk-stack-on-centos-rhel-7 如果你 ...
- redux设计到源码 --- 美团点评技术团队(转)
https://tech.meituan.com/redux-design-code.html
- Docker MySQL基本操作
1 启动mysql实例 docker run --name some-mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:t ...
- django+mysql+html简单demo之 views+html
#coding=utf-8 from __future__ import unicode_literals from django.shortcuts import render,render_to_ ...
- AbstractQueuedSynchronizer,ReentraLock部分代码分析
/* * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * * * * * * * * * * * * * ...
- js 页面间的通信
看了一下公司原来的代码,原页面ajax post返回一个页面完整的HTML,然后再打开一个新页面并输出ajax返回的所有代码到新页面上,在新页面上以表单提交的形式实现重定向. 任凭我想了半天也没想出来 ...
- [作业] Python入门基础---购物车小程序
1.购物车小程序: 1.1用户输入工资取60% 1.2打印输出商品菜单 1.3由用户输入数字选择 #__author:Mifen #date: 2018/11/27 # 购物车程序 #把工资作为账户的 ...