[BZOJ 1535] [Luogu 3426] SZA-Template (KMP + fail doubly linked list trees +)

[BZOJ 1535] [Luogu 3426] SZA-Template (KMP + fail doubly linked list trees +)

Face questions

Byteasar want a long character painted on the wall, he was intercepted in order to do it from the front section of characters in a while as a template. The template is then repeated spraying to the appropriate location after a sequence of characters got what he wanted. a character can be sprayed several times, but the location can not spray a different character. make a template is a waste of effort, so he wanted to stencil length as small as possible, find the minimum length is.

Take a sample for ababbababbabababbabababbababbaba, the template for the first eight characters ababbaba, spraying process is: ababbababbabababbabababbababbaba

analysis

Analysis template string, we will find three properties

Template string properties:

  1. A template is a common prefix and suffix strings required text string B of
  2. If there is a template another template string A string B (i.e. B may cover A), then B is better than A, a solution of
  3. If the number of spaces between strings A template can completely cover the text string B, then A B is matched in position (calculated in accordance with the beginning) does not exceed the length of A

prove:

1. If it is not before the suffix, then the beginning and end would not be able painted

2. Clearly defined by the template string

3. Draw a sample map or look, when spraying must be adjacent or overlapping template sequence

1 by the nature, we found that the template string satisfying the condition must be 1 ~ next [n], or next [next [n]], next [next [next [n]]] ... such substring.

Therefore, we can enumerate the prefix length, and \ (O (n) \) is determined, but this complexity is still \ (O (n ^ 2) \) , and consider optimizing


Then you need to use fail tree.

fail tree, in fact, the position of the mismatch even get up a tree. We respect \ (i \ in [1, the n-] \) , even side \ ((the Next [i], i) \) , \ (the Next [i] \) is \ (i \) father. Because of \ (Next [I] <I \) , even out of a tree must be

Obviously fail root of the tree is 0, x represents the tree node fail text string 1 ~ x bits, the length of the substring of x. And 1 ~ next [n], or next [next [n]], next [next [next [n]]] ... such substring actually fail trees next [n] is a strand 0 ~.

fail tree properties:

Before a common substring represented substring suffix y is represented by x, the point x if and only if y point is the ancestor of

So we can put 0 ~ next [n] mark on the node chain, dfs from the root of the tree fail. Every election in the chain of recursive son node, then remove the other son all nodes in the sub-tree. When using initially a 1 ~ n doubly linked list chain maintaining a distance between adjacent elements (the initial distance of 1, delete x, y in the middle of the distance between a node Z, x, y becomes dist (x , z) + dist (y, z)).

This is easy to see from the number of spaces between the position of the template matching string in the text string . Depending on the nature of the template sequence 3, does not exceed the number of spaces in the length of the template string. And the node x and x represents the length of the substring, thus recursively to $ x \ $ GEQ when the number of spaces, x is the minimum length.

Since each node is deleted at most once, the time complexity \ (O (n) \)


ad:

This question is the idea completely different approach

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define maxn 500000
using namespace std;
struct edge{
    int from;
    int to;
    int next;
}E[maxn*2+5];
int sz=1;
int head[maxn+5];
void add_edge(int u,int v){
    sz++;
    E[sz].from=u;
    E[sz].to=v;
    E[sz].next=head[u];
    head[u]=sz;
}

int n;
char s[maxn+5];
int nex[maxn+5];

struct list{
    int pre[maxn+5],nex[maxn+5];
    int mv;
    void ini(int n){
        mv=1;
        for(int i=1;i<=n;i++){
            pre[i]=i-1;
            nex[i]=i+1;
        }
    }
    void del(int x){
        pre[nex[x]]=pre[x];
        nex[pre[x]]=nex[x];
        mv=max(mv,nex[x]-pre[x]);
        pre[x]=nex[x]=0;
        for(int i=head[x];i;i=E[i].next){
            int y=E[i].to;
            del(y);
        }
    }
    inline int query(){
        return mv;
    }
}S;
int ans=0;
bool mark[maxn+5];
void dfs(int x){//x实际上是某个nex,代表前缀(模板串)长度 
    int to;
    if(S.query()<=x){//模板串性质3 
        ans=x;
        return;
    }
    for(int i=head[x];i;i=E[i].next){
        int y=E[i].to;
        if(mark[y]) to=y;
        else S.del(y);//根据fail树的性质2,把不能匹配的部分去掉,得到两个匹配位置之间的最大距离 
    }
    dfs(to);
} 
int main(){
    scanf("%s",s+1);
    n=strlen(s+1);
    for(int i=2,j=0;i<=n;i++){
        while(j>0&&s[j+1]!=s[i]) j=nex[j];
        if(s[j+1]==s[i]) j++;
        nex[i]=j;
    }
    for(int i=1;i<=n;i++) add_edge(nex[i],i);//建立fail树 
    S.ini(n);
    for(int i=n;i>0;i=nex[i]) mark[i]=1;//模板串性质1 
    dfs(0);
    printf("%d\n",ans);
}

Guess you like

Origin www.cnblogs.com/birchtree/p/11768386.html