bzoj4598 [Sdoi2016]模式字符串 hash+点分
哈希也是有技巧的。不然很容易错。
匹配串范围是1e6的,所以普通hash错误概率也是很大的
所以就要利用匹配的特性(长度与匹配串一一对应)来hash,这样错误概率会小,相当于hash挂链吧。
一开始写的每个前缀hash存位置。这样一个hash里就有1e6个值。
码:
#include<iostream>
#include<cstdio>
#include<vector>
#include<map>
#include<cstring>
#define P 2147483647
#define ll long long
#define D(x) cout<<x<<" ";
using namespace std;
#define N 2000005
#define ll long long
vector<int>v[N];
ll qian[N],hou[N];
int sz[N],fu[N],f[N],g[N],vf[N],vg[N],i,j,n,m,ans,tot,rt,now,T,a,b;
ll ci[N],lin;
char ch[N],S[N];
bool vis[N];
void dfs(int o,int fa)
{
int i,nd;sz[o]=1;fu[o]=fa;for(i=0;i<v[o].size();i++){nd=v[o][i];if(nd==fa||vis[nd])continue;dfs(nd,o);sz[o]+=sz[nd];}
}
void zzx(int o,int qsz)
{int szcnt=0,i,nd,maxx=qsz;for(i=0;i<v[o].size();i++)if(vis[v[o][i]]==0&&fu[o]!=v[o][i])szcnt+=sz[v[o][i]],maxx=max(maxx,sz[v[o][i]]);if(maxx<=tot/2)rt=o; for(i=0;i<v[o].size();i++){ nd=v[o][i];if(nd==fu[o]||vis[nd])continue;zzx(nd,qsz+1+szcnt-sz[nd]); }
}
void Dfs(int o,int fa,ll lin,int dis)
{int i,nd;if(qian[dis]==lin&&vg[m-dis%m-1]==now) //统计答案 ans+=g[m-dis%m-1]; if(hou[dis]==lin&&vf[m-dis%m-1]==now) //统计答案 ans+=f[m-dis%m-1]; for(i=0;i<v[o].size();i++){nd=v[o][i];if(nd==fa||vis[nd])continue;Dfs(nd,o,(lin+(1ll*(ch[nd]-'A'+1)*ci[dis+1])%P)%P,dis+1);}
}
void dfS(int o,int fa,ll lin,int dis)
{int i,nd;if(qian[dis]==lin) //统计答案 {if(vf[dis%m]!=now)vf[dis%m]=now,f[dis%m]=0; f[dis%m]++; }if(hou[dis]==lin) //统计答案 {if(vg[dis%m]!=now)vg[dis%m]=now,g[dis%m]=0; g[dis%m]++; }for(i=0;i<v[o].size();i++){nd=v[o][i];if(nd==fa||vis[nd])continue;dfS(nd,o,(lin+(1ll*(ch[nd]-'A'+1)*ci[dis+1])%P)%P,dis+1);}
}
void solve(int o)
{now=o;int i,nd,hx=ch[o]-'A'+1;
if(qian[0]==hx)vf[0]=o,f[0]=1;
if(hou[0]==hx)vg[0]=o,g[0]=1;
if(vf[0]==o&&vf[0]==vg[m-1])
ans+=g[m-1];for(i=0;i<v[o].size();i++){nd=v[o][i];if(vis[nd])continue;Dfs(nd,o,(hx+(ch[nd]-'A'+1)*ci[1])%P,1);dfS(nd,o,(hx+(ch[nd]-'A'+1)*ci[1])%P,1); }
}
void work(int o)
{vis[o]=1;solve(o);int i,nd;for(i=0;i<v[o].size();i++){nd=v[o][i]; if(vis[nd]||sz[nd]<m)continue;
tot=sz[nd]; dfs(nd,o);zzx(nd,0); dfs(rt,0);
work(rt); }
}
int main()
{ci[0]=1;for(i=1;i<=100000;i++)ci[i]=(ci[i-1]*27)%P;scanf("%d",&T);while(T--){ans=0;memset(vf,0,sizeof(vf));memset(vg,0,sizeof(vg)); memset(vis,0,sizeof(vis));for(i=1;i<=100000;i++)v[i].clear();scanf("%d%d",&n,&m);for(i=1;i<=n;i++){scanf("%c",&ch[i]);while(ch[i]<'A'||ch[i]>'Z')scanf("%c",&ch[i]);}for(i=1;i<n;i++){scanf("%d%d",&a,&b);v[a].push_back(b);v[b].push_back(a);}for(i=1;i<=m;i++){scanf("%c",&S[i]);while(S[i]<'A'||S[i]>'Z')scanf("%c",&S[i]);}
lin=0;
for(i=0;i<=n;i++)
{lin=(lin*27+1ll*(S[(i%m)+1]-'A'+1))%P;qian[i]=lin;
}
lin=0;
for(i=0;i<=n;i++)
{lin=(lin*27+1ll*(S[(m-i%m-1)+1]-'A'+1))%P;hou[i]=lin;
} dfs(1,0);tot=n;zzx(1,0); dfs(rt,0);work(rt); printf("%d\n",ans); }
}
bzoj4598 [Sdoi2016]模式字符串 hash+点分相关推荐
- BZOJ4598: [Sdoi2016]模式字符串
BZOJ4598 求树上满足某些条件的点对,首先就可以想到点分治. 然后又与什么字符串匹配有关.KMP,AC自动机--KMP,AC自动机--之类的好像不太好用..那就哈希吧! 添加答案的时候有两种情况 ...
- Bzoj4598: [Sdoi2016]模式字符串 点分治 哈希
国际惯例的题面: 这种关于树上路径的题,我也没什么好办法,只好点分治. 考虑当前分治重心为root,如何统计经过分治重心的路径的答案. 我们令prf[i]表示某个点到root的路径(不含root)已经 ...
- 【BZOJ4598】[Sdoi2016]模式字符串 树分治+hash
[BZOJ4598][Sdoi2016]模式字符串 Description 给出n个结点的树结构T,其中每一个结点上有一个字符,这里我们所说的字符只考虑大写字母A到Z,再给出长度为m的模式串s,其中每 ...
- 4598: [Sdoi2016]模式字符串
4598: [Sdoi2016]模式字符串 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 80 Solved: 37 [Submit][Statu ...
- BZOJ.4598.[SDOI2016]模式字符串(点分治 Hash)
LOJ BZOJ 洛谷 点分治.考虑如何计算过\(rt\)的答案. 记\(pre[i]\)表示(之前的)子树内循环匹配了\(S\)的前缀\(i\)的路径有多少,\(suf[i]\)表示(之前的)子树内 ...
- bzoj 4598: [Sdoi2016]模式字符串
题目描述 给出n个结点的树结构T,其中每一个结点上有一个字符,这里我们所说的字符只考虑大写字母A到Z,再给出长度为m的模式串s,其中每一位仍然是A到z的大写字母. Alice希望知道,有多少对结点&l ...
- [BZOJ 4598][Sdoi2016]模式字符串
传送门 经典的点分治,hash判断字符串的前缀和后缀: 1 #include <bits/stdc++.h> 2 using namespace std; 3 #define rep(i, ...
- 字符串Hash的原理与应用
字符串Hash无论是在ACM竞赛中还是在工程中都有着广泛的应用,所以很有必要掌握好它的用法.主要分为两个部 分:Hash映射和冲突处理.而本文主要来详细讲解Hash映射的方法及应用,下篇文章将会介绍如 ...
- 字符串hash(二)
从上一届已经讲了字符串hash的方法,hash后怎么用也很重要 文章目录 一.查询子串的hash值 查询子串减去期中一个字符后的hash值 查询两个子串拼接的hash值 **hash的模板(自然溢出) ...
最新文章
- elasticsearch使用jetty进行简单的权限控制
- python 函数 日期区间_python-如何获取两个日期之间的日期
- Hive SQL基础
- xml验证 java代码,使用Java代码进行XML验证
- 终极指南:如何使用Visual Studio Code进行 Java 开发?
- SPI接口比IIC速度快的理解
- 鸿蒙os下载到电脑上,鸿蒙系统pc版下载2.0
- “约见”面试官系列之常见面试题之第六十二篇之IE和兼容下写法(建议收藏)
- SpringBoot 整合 MyCat 实现读写分离
- 三国演义人物出场统计代码含义_Python分析《三国演义》人物出场次数,孔明第二,赵云第五...
- Spring Boot2.0之性能优化
- 路灯干扰者路过时,路灯熄灭的照片
- Js参数RSA加密传输,jsencrypt.js的使用
- docker-compose listing workers for Build: failed to list workers
- Word中大括号内公式左对齐
- NRF24L01使用
- 填坑记录——扫雷游戏的重置
- 4.18耶稣受难日黄金持续跌势(附黄金原油操作建议)
- 合成资产赛道风云突变,Linear Finance有望成为最具潜力的黑马
- GERL 2020 (WWW)Graph Enhanced Representation Learning for News Recommendation
热门文章
- android多个activity绑定一个service,8.1.2 绑定Activity和Service
- 红橙Darren视频笔记 仿QQ侧滑效果
- c++ 数组置0_09c语言数组详解
- python程序多次运行_Python内怎么使同一个.py文件多次运行?
- android 自定义域名,Android基于Retrofit2改造的可设置多域名的网络加载框架
- 运行linux在de1soc,在DE1-SOC上运行Linux
- php exec执行多条命令,小技巧:在PHP中调用多条shell指令
- centos6.8 mysql5.6_Centos6.8 Mysql5.6 安装配置教程(转)
- createprocess重启程序_win32取CreateProcess启动程序的返回值
- Scala go java_Java、Scala和Go语言多线程并发对比测试结果和结论