Bzoj4598: [Sdoi2016]模式字符串 点分治 哈希
国际惯例的题面:
这种关于树上路径的题,我也没什么好办法,只好点分治。
考虑当前分治重心为root,如何统计经过分治重心的路径的答案。
我们令prf[i]表示某个点到root的路径(不含root)已经循环匹配S的前缀到位置i(下标从1开始到m-1,结尾为0)的方案数,suf[i]表示某个点到root的路径(不含root)已经循环匹配S的后缀到位置i(下标从1开始到m-1,结尾为0)的方案数。
对于每一个点,考虑当前这个点到root的路径(不含root)加上root作为前缀或者后缀,能和root的其他子树组成的方案数。
那么我们找到当前的匹配长度,读取一下prf和suf在root的其他子树中的前缀和就好了。(像这种维护二元组数量不算自身对自身的有一个套路,就是让自身和前面的和去计算贡献,这样能保证,每组被计算且仅计算一遍)
因为我们要实现在一个串的前面追加一个字符串并查询字符串是否相等,所以要用到哈希(因为这个相等关系不满足单调性)。
然后就是我智障的故事了:
找重心的时候没有重置maxsiz,导致分治被卡n^2且递归深度很大。
一开始在洛谷RE,八中TLE,表示很不服,然后下载了LOJ的数据。
下来测,TLE,发现找分治重心不太对。
然后造了一条链的数据卡他,本地Linux下RE,第一遍重心都找不到。
调系统错误日志发现是崩栈,果断ulimit -s。
然后还是直播崩栈花式崩栈崩栈到怀疑人生,用那个调日志的root终端,发现ulimit -s出来的数值不一样。
又开了一个终端,发现ulimit -s出来的数值还不一样?这才发现ulimit -s仅单个终端有效!
赶紧用我开过栈的终端运行程序,不崩栈了,TLE了。这才发现找重心的问题。
(我可真是菜,这种水题都一遍写不对)
代码:
#pragma GCC optimize(2)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<iostream>
#define debug cerr
using namespace std;
typedef unsigned long long int ulli;
using std::max;using std::reverse;
const int maxn=1e6+1e2;
const ulli base = ;
const int inf=0x3f3f3f3f; char in[maxn],tar[maxn]; // input string and target string .
ulli pows[maxn],hpr[maxn],hsu[maxn]; // hash prefix and hash suffix .
int s[maxn],t[maxn<<],nxt[maxn<<],ban[maxn],cnt;
int dep[maxn],siz[maxn],mxs[maxn],prf[maxn],suf[maxn],sprf[maxn],ssuf[maxn]; // mxs[0] = inf , paired prf[length] .
int n,m;
ulli ans; bool vis[maxn]; inline void addedge(int from,int to) {
t[++cnt] = to , nxt[cnt] = s[from] ,s[from] = cnt;
}
inline void findroot(int pos,const int &fa,const int &fs,int &rt) {
siz[pos] = , mxs[pos] = ;
for(int at=s[pos];at;at=nxt[at]) if( t[at] != fa && !ban[t[at]] ) {
findroot(t[at],pos,fs,rt) , siz[pos] += siz[t[at]] , mxs[pos] = max( mxs[pos] , siz[t[at]] );
}
if( ( mxs[pos] = max( mxs[pos] , fs - siz[pos] ) ) <= mxs[rt] ) rt = pos;
}
inline void dfs(int pos,int fa,int dep,int &mxd,const char &mid,ulli h) {
mxd = max( mxd , dep ) , h += in[pos] * pows[dep-]; // add in[pos] to first char .
if( h == hpr[dep] ) {
++prf[dep%m];
if( mid == tar[dep%m+] ) ans += ssuf[m-dep%m-];
}
if( h == hsu[dep] ) {
++suf[dep%m];
if( mid == tar[m-dep%m] ) ans += sprf[m-dep%m-];
}
for(int at=s[pos];at;at=nxt[at]) if( t[at] != fa && !ban[t[at]] ) dfs(t[at],pos,dep+,mxd,mid,h);
}
inline void solve(int pos,int fs) {
if( fs < m ) return;
int rt = , full = ;
*mxs = inf , findroot(pos,-,fs,rt) , ban[rt] = ;
if( in[rt] == tar[] ) ++sprf[];
if( in[rt] == tar[m] ) ++ssuf[];
for(int at=s[rt],mxd;at;at=nxt[at]) if( !ban[t[at]] ) {
mxd = , dfs(t[at],rt,,mxd,in[rt],) , full = max( full , mxd );
for(int i=;i<=mxd;i++) sprf[i] += prf[i] , ssuf[i] += suf[i] , prf[i] = suf[i] = ;
}
for(int i=;i<=full;i++) sprf[i] = ssuf[i] = ;
for(int at=s[rt];at;at=nxt[at]) if( !ban[t[at]] ) solve(t[at],siz[t[at]]<siz[rt]?siz[t[at]]:fs-siz[rt]);
} inline char nextchar() {
static const int BS = << ;
static char buf[BS],*st=buf+BS,*ed=buf+BS;
if( st == ed ) ed = buf + fread(st=buf,,BS,stdin);
return st == ed ? - : *st++;
}
inline int getint() {
int ret = , ch;
while( !isdigit(ch=nextchar()) );
do ret = ret * + ch - ''; while( isdigit(ch=nextchar()) );
return ret;
}
inline void getstr(char* s) {
char ch;
while( !isalpha(ch=nextchar()) );
do *s++ = ch; while( isalpha(ch=nextchar()) );
}
inline void gethsh(ulli* dst) {
for(int i=m+;i<=n;i++) tar[i] = tar[i-m];
for(int i=;i<=n;i++) dst[i] = dst[i-] * base + tar[i];
}
inline void fix(char* s,int len) {
for(int i=;i<=len;i++) s[i] -= 'A' - ;
}
inline void solve_case() {
n = getint() , m = getint() , getstr(in+) , fix(in,n) , memset(s,,sizeof(s)) , memset(ban,,sizeof(ban)) , cnt = ans = , *pows = ;
for(int i=;i<=n;i++) pows[i] = pows[i-] * base;
for(int i=,a,b;i<n;i++) a = getint() , b = getint() , addedge(a,b) , addedge(b,a);
getstr(tar+) , fix(tar,m) , gethsh(hpr) , reverse(tar+,tar++m) , gethsh(hsu) , reverse(tar+,tar++m);
solve(,n) , printf("%llu\n",ans);
} int main() {
static int T;
T = getint();
while(T--) solve_case();
return ;
}
话说我自带大常数的代码竟然跑到了第一页?
変わらない毎日めぐりめぐる
不变的每日一天又一天
何も無い時間が過ぎる
流逝着无所事事的时间
風にゆらめいて歩き出せば
如果在风中飘舞着迈出步伐
いつか変わるかな? 明日
明天总会有所改变的吧?
無くしたものを 探しては あきらめて
已逝之物 探寻又放弃
一人佇み 空を見ていた
就这么一个人站着 看着天空
Bzoj4598: [Sdoi2016]模式字符串 点分治 哈希的更多相关文章
- BZOJ4598: [Sdoi2016]模式字符串(点分治 hash)
题意 题目链接 Sol 直接考虑点分治+hash匹配 设\(up[i]\)表示\(dep \% M = i\)的从下往上恰好与前\(i\)位匹配的个数 \(down\)表示\(dep \% M = i ...
- 【BZOJ4598】[Sdoi2016]模式字符串 树分治+hash
[BZOJ4598][Sdoi2016]模式字符串 Description 给出n个结点的树结构T,其中每一个结点上有一个字符,这里我们所说的字符只考虑大写字母A到Z,再给出长度为m的模式串s,其中每 ...
- BZOJ4598 [Sdoi2016]模式字符串 【点分治 + hash】
题目 给出n个结点的树结构T,其中每一个结点上有一个字符,这里我们所说的字符只考虑大写字母A到Z,再给出长度为m 的模式串s,其中每一位仍然是A到z的大写字母.Alice希望知道,有多少对结点< ...
- bzoj4598: [Sdoi2016]模式字符串
Description 给出n个结点的树结构T,其中每一个结点上有一个字符,这里我们所说的字符只考虑大写字母A到Z,再给出长度为m 的模式串s,其中每一位仍然是A到z的大写字母.Alice希望知道,有 ...
- BZOJ.4598.[SDOI2016]模式字符串(点分治 Hash)
LOJ BZOJ 洛谷 点分治.考虑如何计算过\(rt\)的答案. 记\(pre[i]\)表示(之前的)子树内循环匹配了\(S\)的前缀\(i\)的路径有多少,\(suf[i]\)表示(之前的)子树内 ...
- 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希望知道,有多 ...
随机推荐
- Docker相关
1.理念 通过对应用组件的封装.分发.部署.运行等生命周期的管理,使用户的App(可以是一个Web应用或数据库应用等)及其运行环境能够做到“一次封装,处处运行”. 2.一句话总结 解决运行环境和配置问 ...
- javascript随笔和常见的知识点
1.js中循环中用 return只能停止循环,不能停止到函数的定义部分.所以下面的返回值为1 return 100没有意义,只起到终止循环的目的 function bb() { var sum = 0 ...
- 深入理解linux内核v4l2框架之videobuf2【转】
转自:https://blog.csdn.net/ramon1892/article/details/8444193 Videobuf2框架 1. 什么是videobuf2框架? 它是一个针对多媒体设 ...
- mysql删除数据库文件ibdata1后引发的故障
进行性能测试是发现大量报错: Duplicate entry主键重复 可以看到mysql数据库中已经没有innodb引擎启动信息了 之前发现ibdata1占用了大量硬盘,为了省出空间删除了数据库ibd ...
- linux设备模型:扩展篇
Linux设备模型组件:总线 一.定义:总线是不同IC器件之间相互通讯的通道;在计算机中,一个总线就是处理器与一个或多个不同外设之间的通讯通道;为了设备模型的目的,所有的设备都通过总线相互连接,甚至 ...
- [java]用md5来判断两个文件是否完全相同
1. 前言 由于相比较两张图片是否是相同,如果通过像素点比较感觉速度比较慢,当很多图片进行比较时,效率就低很多了.由于每个文件md5基本上是唯一的,所以用获取文件的md5来判断是否相同文件. 2. 代 ...
- Java基础94 分页查询(以MySQL数据库为例)
1.概述 分页查询,也可叫做分批查询,基于数据库的分页语句(不同数据库是不同的). 本文使用的事MySql数据库. 假设:每页显示10条数据. Select * from c ...
- MySQL 5.6.26几种安装包的区别
一.MySQL Installer 5.6.26 mysql-installer-community-5.6.26.0.msi, 364.2MBMySQL Installer 提供了简单易用.向导式的 ...
- ctype
original:http://www.runoob.com/cprogramming/c-standard-library-ctype-h.html 下面列出了头文件 ctype.h 中定义的函数: ...
- Python decorator
1.编写无参数的decorator Python的 decorator 本质上就是一个高阶函数,它接收一个函数作为参数,然后,返回一个新函数. 使用 decorator 用Python提供的 @ 语法 ...