字符串专题-扩展KMP

时间:2023-01-03 16:19:41

字符串专题-扩展KMP

思路:乍一看就是扩展KMP,但这题还是要一点点转化。
如果想要满足题目要求,匹配段肯定间隔是相反的。
比如样例中在0位置匹配:
1 (+3)4(+2) 6 9
5 (-3)2 (-2) 0
Code:

#include <bits/stdc++.h>
using namespace std;
const int AX = 1e5+66; 
int n , m;
int a[AX];
int b[AX];
int sa[AX];
int sb[AX];
int next1[AX];
int extend[AX];
int res ;
int re[AX];
void getNext(){
    int i = 0, po = 0;
    int len = m - 1;
    next1[0] = len;
    while( i + 1 < len && sb[i] == sb[i+1] ) i++;
    next1[1] = i;
    po = 1;
    for( int i = 2 ; i < len ; i++ ){
        if( po + next1[po] > i + next1[i-po] ){
            next1[i] = next1[i-po];
        }else{
            int j = next1[po] + po - i;
            if( j < 0 ) j = 0 ;
            while( i + j < len && sb[i+j] == sb[j] ) j++;
            next1[i] = j ;
            po = i;
        }
    }
}

void getExtend(){
    int i = 0 , po;
    int len = n - 1;
    int lenm = m - 1;
    getNext();
    while( i < len && i < lenm && sa[i] == sb[i] ) i++;
    extend[0] = i;
    po = 0;
    if( extend[0] == lenm ) {
        re[res++] = 0;
    }
    for( int i = 1 ; i < len ; i++ ){
        if( po + extend[po] > i + next1[i-po] ){
            extend[i] = next1[i-po];
        }else{
            int j = extend[po] + po - i;
            if( j < 0 ) j = 0;
            while( i + j < len && j < lenm && sa[i+j] == sb[j] ) j++;
            extend[i] = j;
            po = i;
        }
        if( extend[i] == lenm ){
            re[res++] = i;
        }
    }
}
int main(){
    res = 0;
    scanf("%d%d",&n,&m);
    for( int i = 0 ; i < n ; i++ ){
        scanf("%d",&a[i]);
        if( i ) sa[i-1] = 0-(a[i] - a[i-1]);
    }
    for( int i = 0 ; i < m ; i++ ){
        scanf("%d",&b[i]);
        if( i ) sb[i-1] = b[i] - b[i-1];
    }
    getExtend();
    printf("%d\n",res);
    for( int i = 0 ; i < res ;i ++ ){
        printf("%d ",re[i]);
    }printf("\n");
    return 0 ;
}