bzoj4641基因改造 特殊匹配条件的KMP
Posted GXZlegend
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4641基因改造 特殊匹配条件的KMP相关的知识,希望对你有一定的参考价值。
题目描述
如果两个长度相等的字符串,如果存在一种字符的一一映射,使得第一个字符串的所有字符经过映射后与第二个字符串相同,那么就称它们“匹配”。现在给出两个串,求第一个字符串所有长度等于第二个字符串的长度的子串中与第二个字符串“匹配”的所有子串的位置。
输入
输出
样例输入
3 3
6 3
1 2 1 2 3 2
3 1 3
6 3
1 2 1 2 1 2
3 1 3
6 3
1 1 2 1 2 1
3 1 3
样例输出
3
1 2 4
4
1 2 3 4
3
2 3 4
题解
特殊匹配条件的KMP
本题和 【bzoj2384】[Ceoi2011]Match 类似。
考虑什么样的两个串是“匹配”的:每个位置数的上一次出现位置与其距离相同。
那么可以把每个位置的权值当作该数上一次出现的位置与其的距离,然后跑KMP即可。
这里需要注意的一点是,在求next数组和匹配时,如果一个位置的上一次出现位置与其距离大于当前串长(这种情况在求next计算后半部分,以及匹配时的母串中出现),那么应当视为该数没有出现过,需要特殊处理。
时间复杂度 $O(n)$
#include <cstdio> #include <cctype> #include <cstring> #define N 1000010 int pa[N] , pb[N] , pos[N] , next[N] , ans[N]; inline char nc() { static char buf[100000] , *p1 , *p2; return p1 == p2 && (p2 = (p1 = buf) + fread(buf , 1 , 100000 , stdin) , p1 == p2) ? EOF : *p1 ++ ; } inline int read() { int ret = 0; char ch = nc(); while(!isdigit(ch)) ch = nc(); while(isdigit(ch)) ret = ((ret + (ret << 2)) << 1) + (ch ^ \'0\') , ch = nc(); return ret; } int main() { int T = read(); read(); while(T -- ) { int n = read() , m = read() , i , j , x , tot = 0; memset(pos , -1 , sizeof(pos)); for(i = 0 ; i < n ; i ++ ) x = read() , pa[i] = (~pos[x] ? i - pos[x] : -1) , pos[x] = i; memset(pos , -1 , sizeof(pos)); for(i = 0 ; i < m ; i ++ ) x = read() , pb[i] = (~pos[x] ? i - pos[x] : -1) , pos[x] = i; next[0] = -1; for(i = 1 , j = -1 ; i <= m ; i ++ ) { while(~j && pb[i - 1] != pb[j] && !(pb[i - 1] > j && pb[j] == -1)) j = next[j]; next[i] = ++j; } for(i = j = 0 ; i < n ; i ++ ) { while(~j && pa[i] != pb[j] && !(pa[i] > j && pb[j] == -1)) j = next[j]; if(++j == m) ans[++tot] = i - m + 2 , j = next[j]; } printf("%d\\n" , tot); for(i = 1 ; i <= tot ; i ++ ) printf("%d " , ans[i]); printf("\\n"); } return 0; }
以上是关于bzoj4641基因改造 特殊匹配条件的KMP的主要内容,如果未能解决你的问题,请参考以下文章
bzoj2384[Ceoi2011]Match 特殊匹配条件的KMP+树状数组
BZOJ1264 [AHOI2006]基因匹配Match 动态规划 树状数组
bzoj1264 [AHOI2006]基因匹配Match 树状数组+lcs
BZOJ 1264 AHOI2006 基因匹配Match 动态规划+树状数组