题面

洛谷P5410 【模板】扩展 KMP(Z 函数)

给定两个字符串 \(a,b\),要求出两个数组:\(b\) 的 \(z\) 函数数组 \(z\)、\(b\) 与 \(a\) 的每一个后缀的 LCP 长度数组 \(p\)。

数据范围:\(1\le |a|,|b|\le 2\times 10^7\)。


蒟蒻语

别的题解为什么代码那么长、讲解那么复杂?蒟蒻不解,写篇易懂一点的,希望没有错误理解。

注意:蒟蒻的下标是从 \(0\) 开始的。


蒟蒻解

定义 \(z(i) (i>0)\):后缀 \(i\) 与字符串的 LCP 长度,劝退一点地说:

\[z(i)=\max_{len=1}^{|s|-i} \left(len\cdot [\forall 0\le x<len,s[(0)+(x)]=s[(i)+(x)]]\right)
\]

对于求字符串 \(s\) 的 \(z\) 函数,可以用递推解决一部分问题,蒟蒻先放上精美的代码:

这里特定 \(z(0)=0\)(题目中 \(z(0)=|s|\))。

  1. void getz(string s){
  2. int l=0;
  3. R(i,1,sz(s)){
  4. if(l+z[l]>i) z[i]=min(z[i-l],l+z[l]-i);
  5. while(i+z[i]<sz(s)&&s[z[i]]==s[i+z[i]]) z[i]++;
  6. if(i+z[i]>l+z[l]) l=i;
  7. }
  8. // R(i,0,sz(s)) cout<<z[i]<<" ";cout<<'\n';
  9. }

结论: 对于 \(i>0\),对任意 \(0\le l<i\) 都可以递推得:

\[\forall 0\le x<\min(z(i-l),l+z(l)-i),s[(i)+(x)]=s[(0)+(x)]
\]

证明:

\[\begin{aligned}
&s[(i)+(x)]\\
=&s[(l)+(i+x-l)]\\
=&s[(0)+(i+x-l)]\color{red}{(x\le l+z(l)-i)}\\
=&s[(i-l)+(x)]\\
=&s[(0)+(x)]\color{red}{(x\le z(i-l))}\\
\end{aligned}
\]

所以可以选定某个 \(0\le l<i\),初始化 \(z(i)=\min(z(i-l),l+z(l)-i)\),然后暴力判断字符相等增加 \(z(i)\)。

这里 \(l\) 选满足 \(j+z(j)(0\le j<i)\) 最大的 \(j\),这样每个字符只会被暴力判断一次,所以时间复杂度可以做到 \(\Theta(n)\)。

对于题目中的问题其实把 \(b\) 和 \(a\) 接起来做个 \(z\) 就可以了。


代码

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. //Start
  4. typedef long long ll;
  5. typedef double db;
  6. #define mp(a,b) make_pair((a),(b))
  7. #define x first
  8. #define y second
  9. #define Be begin()
  10. #define En end()
  11. #define sz(a) int((a).size())
  12. #define pb(a) push_back(a)
  13. #define R(i,a,b) for(int i=(a),I=(b);i<I;i++)
  14. #define L(i,a,b) for(int i=(b)-1,I=(a)-1;i>I;i--)
  15. const int iinf=0x3f3f3f3f;
  16. const ll linf=0x3f3f3f3f3f3f3f3f;
  17. //Data
  18. const int N=2e7;
  19. ll ansz,ansp;
  20. string a,b;
  21. //Zfunction
  22. int z[N<<1];
  23. void getz(string s){
  24. int l=0;
  25. R(i,1,sz(s)){
  26. if(l+z[l]>i) z[i]=min(z[i-l],l+z[l]-i);
  27. while(i+z[i]<sz(s)&&s[z[i]]==s[i+z[i]]) z[i]++;
  28. if(i+z[i]>l+z[l]) l=i;
  29. }
  30. // R(i,0,sz(s)) cout<<z[i]<<" ";cout<<'\n';
  31. }
  32. //Main
  33. int main(){
  34. ios::sync_with_stdio(0);
  35. cin.tie(0),cout.tie(0);
  36. cin>>a>>b,getz(b+a);
  37. ansz^=1ll*(sz(b)+1)*(0+1);
  38. R(i,1,sz(b)) ansz^=1ll*(min(z[i],sz(b)-i)+1)*(i+1);
  39. R(i,0,sz(a)) ansp^=1ll*(min(z[i+sz(b)],sz(b))+1)*(i+1);
  40. cout<<ansz<<'\n'<<ansp<<'\n';
  41. return 0;
  42. }

祝大家学习愉快!

题解-洛谷P5410 【模板】扩展 KMP(Z 函数)的更多相关文章

  1. luogu P5410 模板 扩展 KMP Z函数 模板

    LINK:P5410 模板 扩展 KMP Z 函数 画了10min学习了一下. 不算很难 思想就是利用前面的最长匹配来更新后面的东西. 复杂度是线性的 如果不要求线性可能直接上SA更舒服一点? 不管了 ...

  2. [洛谷P4720] [模板] 扩展卢卡斯

    题目传送门 求组合数的时候,如果模数p是质数,可以用卢卡斯定理解决. 但是卢卡斯定理仅仅适用于p是质数的情况. 当p不是质数的时候,我们就需要用扩展卢卡斯求解. 实际上,扩展卢卡斯=快速幂+快速乘+e ...

  3. [洛谷P4777] [模板] 扩展中国剩余定理

    扩展中国剩余定理,EXCRT. 题目传送门 重温一下中国剩余定理. 中国剩余定理常被用来解线性同余方程组: x≡a[1] (mod m[1]) x≡a[2] (mod m[2]) ...... x≡a ...

  4. 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)

    To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...

  5. 题解-洛谷P4724 【模板】三维凸包

    洛谷P4724 [模板]三维凸包 给出空间中 \(n\) 个点 \(p_i\),求凸包表面积. 数据范围:\(1\le n\le 2000\). 这篇题解因为是世界上最逊的人写的,所以也会有求凸包体积 ...

  6. 洛谷P3375 [模板]KMP字符串匹配

    To 洛谷.3375 KMP字符串匹配 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果 ...

  7. LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)

    为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...

  8. 【AC自动机】洛谷三道模板题

    [题目链接] https://www.luogu.org/problem/P3808 [题意] 给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过. [题解] 不再介绍基础知识了,就是裸的模 ...

  9. 题解-洛谷P6788 「EZEC-3」四月樱花

    题面 洛谷P6788 「EZEC-3」四月樱花 给定 \(n,p\),求: \[ans=\left(\prod_{x=1}^n\prod_{y|x}\frac{y^{d(y)}}{\prod_{z|y ...

随机推荐

  1. MySQL死锁问题(转)

    线上某服务时不时报出如下异常(大约一天二十多次):"Deadlock found when trying to get lock;". Oh, My God! 是死锁问题.尽管报错 ...

  2. 有名管道FIFO进程间数据传输实例

    紧接着上面一个博客的简单介绍,下面进行一个没有血缘关系的进程间通信的实例,实现文件拷贝传输. 有两个进程,一个主要是fifow进程:读文件Makefile内容,写入管道;另一个进程fifor:读管道内 ...

  3. Windows10系统下使用Docker搭建ClickHouse开发环境

    前提 随着现在业务开展,几个业务系统的数据量开始急剧膨胀.之前使用了关系型数据库MySQL进行了一次数据仓库的建模,发现了数据量上来后,大量的JOIN操作在提高了云MySQL的配置后依然有点吃不消,加 ...

  4. [LeetCode题解]160. 相交链表 | 双指针 + 哈希表

    方法一:双指针 解题思路 假设链表存在相交时,headA 的长度为 a + c,headB 的长度为 b + c.如果把 headA 连上 headB,headB 连上 headB 的话,当遍历这两个 ...

  5. CTF-Web-强网杯 2019-随便注

    题目链接 题目链接-supersqli FUZZ测试 fuzz出,order by测出数据库查询列数2列,注释符号#,select|update|delete|drop|insert|where|被过 ...

  6. python多线程——如何停止一个死循环的线程

    进程想要执行任务就需要依赖线程.换句话说,就是进程中的最小执行单位就是线程,并且一个进程中至少有一个线程. 那什么是多线程?提到多线程这里要说两个概念,就是串行和并行,搞清楚这个,我们才能更好地理解多 ...

  7. IDM中的选项设置你了解多少?

    IDM(Internet Download Manager)下载器能够兼容支持多种浏览器进行文件下载,很多时候只要复制一个地址IDM的下载弹窗就自动弹出来,有时候不需要下载的时候也会弹,时间久了就会感 ...

  8. MathType中余弦函数的输入

    余弦函数是三角函数中十分重要的一个知识点,余弦函数的俩种形式分别为a2=b2+c2-2bccosA和cosA=(b2+c2-a2)/2bc,接下来我们分别介绍一下这俩种形式的输入. 具体步骤如下: 步 ...

  9. H5系列之常用的语义元素

    H5添加了几个新标签,带有语义化的标签,像我们的div 和 span 标签,你说他两能干嘛呢, 好像他两什么事都能干.举个例子,你家里的房子,有几个房间,如果不分房间的话,是不是你 今天睡这里,明天睡 ...

  10. 2. git命令行操作之本地库操作

    2.1 本地库初始化 git init 命令 用于创建一个空的Git本地仓库或重新初始化一个现有本地仓库 注:.git目录中存放的是本地库相关的子目录和文件,不要删除也不要随意修改 git confi ...