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

题目链接

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

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

题目描述

给定两个字符串 a,b,你要求出两个数组:

  • bz 函数数组 z,即 bb 的每一个后缀的 LCP 长度。
  • ba 的每一个后缀的 LCP 长度数组 p

对于一个长度为 n 的数组 a,设其权值为 xori=1ni×(ai+1)

输入格式

两行两个字符串 a,b

输出格式

第一行一个整数,表示 z 的权值。

第二行一个整数,表示 p 的权值。

样例 #1

样例输入 #1

aaaabaa aaaaa

样例输出 #1

6 21

提示

样例解释:

z={5 4 3 2 1}p={4 3 2 1 0 2 1}


数据范围:

对于第一个测试点,|a|,|b|2×103

对于第二个测试点,|a|,|b|2×105

对于 100% 的数据,1|a|,|b|2×107,所有字符均为小写字母。

解题思路

z函数

z函数即exkmp
对于一个长度为 n 的字符串 s,定义函数 z[i] 表示 ss[i,n1] 的的最长公共前缀长度,注意后面算法求z函数时特定 z[0]=0
算法流程:主要核心在求 z[i] 时要利用前面 z[0],z[1],,z[i1] 的信息,从 i=1 开始,对于每个 i 来说,都有一个匹配段 [i,r],维护其中 r 最大的匹配段 [l,r],如果 ir,则有 s[i,r]=s[il,rl],则有 z[i]min(z[il],ri+1),如果 z[il]<ri+1,则 z[i]=z[il],否则令 z[i]=ri+1,暴力往后扩展;否则如果 i>r,则暴力求解

这个算法只能求解 s 本身的z函数,st不妨令s=s+t,从 len(s) 的位置开始计算z函数,另外需要注意 z[i]len(s)

复杂度分析:每次 while 时,r 都至少增加一次,即 while 的总的执行次数为 O(n),则:

  • 时间复杂度:O(n)

代码

// Problem: P5410 【模板】扩展 KMP(Z 函数) // Contest: Luogu // URL: https://www.luogu.com.cn/problem/P5410 // Memory Limit: 500 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> // #define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=4e7+5; int n,m; char s[N>>1],t[N]; vector<int> z_function(char *s) { int n=strlen(s); vector<int> z(n); for(int i=1,l=0,r=0;i<n;i++) { if(i<=r&&z[i-l]<r-i+1)z[i]=z[i-l]; else { z[i]=max(0,r-i+1); while(i+z[i]<n&&s[z[i]]==s[i+z[i]])z[i]++; } if(i+z[i]-1>r)l=i,r=i+z[i]-1; } return z; } int main() { scanf("%s%s",s,t); n=strlen(t); strcat(t+n,t); vector<int> z=z_function(t); LL res=0; for(int i=n;i<2*n;i++)res^=(LL)(i-n+1)*(min(z[i],n)+1); printf("%lld\n",res); t[n]='\0'; m=strlen(s); strcat(t+n,s); z=z_function(t); res=0; for(int i=n;i<n+m;i++)res^=(LL)(i-n+1)*(min(z[i],n)+1); printf("%lld\n",res); return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16973409.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(52)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示