BZOJ 4032 HEOI2015 最短不公共子串 后缀自动机+序列自动机+BFS

题目大意:给定字符串A和B,求A最短的子串/子序列S满足S不是B的子串/子序列

这题真TM有毒*2

搞法类似这道题

然后子串是后缀自动机 子序列自然就是序列自动机了= =

每更新一个x节点时所有没有x的后继的节点都连向这个节点

每个节点的parent是这个字母上一次出现的位置

每个字母记录最后一次出现的位置 更新指针时沿着parent指针撸一遍就行了

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 4040
using namespace std;
char A[M],B[M];
struct Suffix_Automaton{
    struct Sam{
        Sam *son[26],*parent;
        int max_dpt;
        Sam() {}
        Sam(int _):max_dpt(_) {}
    }mempool[M],*C;
    Sam *root,*last;
    Suffix_Automaton()
    {
        C=mempool;
        last=root=new (C++)Sam(0);
    }
    void Extend(int x)
    {
        Sam *p=last;
        Sam *np=new (C++)Sam(p->max_dpt+1);
        for(;p&&!p->son[x];p=p->parent)
            p->son[x]=np;
        if(!p)
            np->parent=root;
        else
        {
            Sam *q=p->son[x];
            if(p->max_dpt+1==q->max_dpt)
                np->parent=q;
            else
            {
                Sam *nq=new (C++)Sam(p->max_dpt+1);
                memcpy(nq->son,q->son,sizeof nq->son);
                nq->parent=q->parent;
                q->parent=nq;np->parent=nq;
                for(;p&&p->son[x]==q;p=p->parent)
                    p->son[x]=nq;
            }
        }
        last=np;
    }
}substr_A,substr_B;
struct Sequence_Automaton{
    struct Sqa{
        Sqa *son[26],*parent;
    }mempool[M],*C;
    Sqa *root,*last[27];
    Sequence_Automaton()
    {
        C=mempool;
        last[26]=root=new (C++)Sqa;
    }
    void Extend(int x)
    {
        Sqa *p,*np=new (C++)Sqa;
        int i;
        for(i=0;i<=26;i++)
            for(p=last[i];p&&!p->son[x];p=p->parent)
                p->son[x]=np;
        np->parent=last[x];
        last[x]=np;
    }
}subseq_A,subseq_B;
struct abcd{
    int x,y,dpt;
    abcd() {}
    abcd(int _,int __,int ___):
        x(_),y(__),dpt(___) {}
}q[M];
int v[M][M];
int BFS1()//str-str
{
    int i,r=0,h=0;
    q[++r]=abcd(0,0,0);
    v[0][0]=true;
    while(r!=h)
    {
        abcd sta=q[++h];
        for(i=0;i<26;i++)
        {
            if(!substr_A.mempool[sta.x].son[i]) continue;
            if(!substr_B.mempool[sta.y].son[i]) return sta.dpt+1;
            int xx=substr_A.mempool[sta.x].son[i]-substr_A.root;
            int yy=substr_B.mempool[sta.y].son[i]-substr_B.root;
            if(v[xx][yy]==1) continue;
            v[xx][yy]=1;
            q[++r]=abcd(xx,yy,sta.dpt+1);
        }
    }
    return -1;
}
int BFS2()//str-seq
{
    int i,r=0,h=0;
    q[++r]=abcd(0,0,0);
    v[0][0]=true;
    while(r!=h)
    {
        abcd sta=q[++h];
        for(i=0;i<26;i++)
        {
            if(!substr_A.mempool[sta.x].son[i]) continue;
            if(!subseq_B.mempool[sta.y].son[i]) return sta.dpt+1;
            int xx=substr_A.mempool[sta.x].son[i]-substr_A.root;
            int yy=subseq_B.mempool[sta.y].son[i]-subseq_B.root;
            if(v[xx][yy]==2) continue;
            v[xx][yy]=2;
            q[++r]=abcd(xx,yy,sta.dpt+1);
        }
    }
    return -1;
}
int BFS3()//seq-str
{
    int i,r=0,h=0;
    q[++r]=abcd(0,0,0);
    v[0][0]=true;
    while(r!=h)
    {
        abcd sta=q[++h];
        for(i=0;i<26;i++)
        {
            if(!subseq_A.mempool[sta.x].son[i]) continue;
            if(!substr_B.mempool[sta.y].son[i]) return sta.dpt+1;
            int xx=subseq_A.mempool[sta.x].son[i]-subseq_A.root;
            int yy=substr_B.mempool[sta.y].son[i]-substr_B.root;
            if(v[xx][yy]==3) continue;
            v[xx][yy]=3;
            q[++r]=abcd(xx,yy,sta.dpt+1);
        }
    }
    return -1;
}
int BFS4()//seq-seq
{
    int i,r=0,h=0;
    q[++r]=abcd(0,0,0);
    v[0][0]=true;
    while(r!=h)
    {
        abcd sta=q[++h];
        for(i=0;i<26;i++)
        {
            if(!subseq_A.mempool[sta.x].son[i]) continue;
            if(!subseq_B.mempool[sta.y].son[i]) return sta.dpt+1;
            int xx=subseq_A.mempool[sta.x].son[i]-subseq_A.root;
            int yy=subseq_B.mempool[sta.y].son[i]-subseq_B.root;
            if(v[xx][yy]==4) continue;
            v[xx][yy]=4;
            q[++r]=abcd(xx,yy,sta.dpt+1);
        }
    }
    return -1;
}
int main()
{
    //freopen("sus.in","r",stdin);
    //freopen("sus.out","w",stdout);
    int i;
    scanf("%s%s",A+1,B+1);
    for(i=1;A[i];i++)
    {
        substr_A.Extend(A[i]-‘a‘);
        subseq_A.Extend(A[i]-‘a‘);
    }
    for(i=1;B[i];i++)
    {
        substr_B.Extend(B[i]-‘a‘);
        subseq_B.Extend(B[i]-‘a‘);
    }
    cout<<BFS1()<<endl;
    cout<<BFS2()<<endl;
    cout<<BFS3()<<endl;
    cout<<BFS4()<<endl;
    return 0;
}
时间: 2024-12-05 15:07:18

BZOJ 4032 HEOI2015 最短不公共子串 后缀自动机+序列自动机+BFS的相关文章

【BZOJ】4032: [HEOI2015]最短不公共子串(LibreOJ #2123)

[题意]给两个小写字母串A,B,请你计算: (1) A的一个最短的子串,它不是B的子串 (2) A的一个最短的子串,它不是B的子序列 (3) A的一个最短的子序列,它不是B的子串 (4) A的一个最短的子序列,它不是B的子序列 不存在输出-1,1<=len(A),len(B)<=2000. [算法]后缀自动机+序列自动机 [题解]后缀自动机用于识别 原文地址:https://www.cnblogs.com/onioncyc/p/8192581.html

【BZOJ4032】【HEOI2015】最短不公共子串 后缀自动机

链接: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/45313429"); } 题解: T1: 我们按长度bfs所有的串,对于每个串记录A串中终点位置.B串中终点位置(B串中位置由B的后缀自动机中节点标号表示).长度--(x,y,l). 然后 (x,y,l) 可以 O(1) 转移到 (x

bzoj4032: [HEOI2015]最短不公共子串

Description 在虐各种最长公共子串.子序列的题虐的不耐烦了之后,你决定反其道而行之. 一个串的“子串”指的是它的连续的一段,例如bcd是abcdef的子串,但bde不是. 一个串的“子序列”指的是它的可以不连续的一段,例如bde是abcdef的子串,但bdd不是. 下面,给两个小写字母串A,B,请你计算: (1) A的一个最短的子串,它不是B的子串 (2) A的一个最短的子串,它不是B的子序列 (3) A的一个最短的子序列,它不是B的子串 (4) A的一个最短的子序列,它不是B的子序列

BZOJ 2946 POI2000 公共串 后缀自动机(多串最长公共子串)

题意概述:给出N个字符串,每个串的长度<=2000(雾...可能是当年的年代太久远机子太差了),问这N个字符串的最长公共子串长度为多少.(N<=5) 抛开数据结构,先想想朴素做法. 设计一种稳定的暴力算法.可以想到这样一种做法:首先确定一个串,枚举每个位置,然后暴力计算其他每个串以这个位置开头的最长匹配,取最小值,就是在公共子串在我们确定下来的串的这个位置开头的时候所能得到的最长公共子串.不难发现把这个问题转化成后缀的形式也是一样的.同时发现可能在枚举多个位置的时候答案甚至最后构造出来的串都是

后缀数组(多个字符串的最长公共子串)—— POJ 3294

对应POJ 题目:点击打开链接 Life Forms Time Limit:6666MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Description Problem C: Life Forms You may have wondered why most extraterrestrial life forms resemble humans, differing by superficial tra

BZOJ 2946 Poi2000 公共串 后缀自动机

题目大意:求n个串的最长公共子串 太久没写SAM了真是-- 将第一个串建成后缀自动机,用其它的串进去匹配 每个节点记录每个串在上面匹配的最大长度 那么这个节点对答案的贡献就是所有最大长度的最小值 对所有贡献取最大就行了= = 这最大最小看着真是别扭 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 10100 using namesp

HDU 1403 Longest Common Substring(后缀数组,最长公共子串)

hdu题目 poj题目 参考了 罗穗骞的论文<后缀数组——处理字符串的有力工具> 题意:求两个序列的最长公共子串 思路:后缀数组经典题目之一(模版题) //后缀数组sa:将s的n个后缀从小到大排序后将 排序后的后缀的开头位置 顺次放入sa中,则sa[i]储存的是排第i大的后缀的开头位置.简单的记忆就是“排第几的是谁”. //名次数组rank:rank[i]保存的是suffix(i){后缀}在所有后缀中从小到大排列的名次.则 若 sa[i]=j,则 rank[j]=i.简单的记忆就是“你排第几”

POJ 2774 后缀数组:求最长公共子串

思路:其实很简单,就是两个字符串连接起来,中间用个特殊字符隔开,然后用后缀数组求最长公共前缀,然后不同在两个串中,并且最长的就是最长公共子串了. 注意的是:用第一个字符串来判断是不是在同一个字符中,刚开始用了第二个字符的长度来判断WA了2发才发现. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<

poj 2774 最长公共子串--字符串hash或者后缀数组或者后缀自动机

http://poj.org/problem?id=2774 想用后缀数组的看这里:http://blog.csdn.net/u011026968/article/details/22801015 本文主要讲下怎么hash去找 开始的时候写的是O(n^2 logn)算法 果断超时...虽然也用了二分的,, 代码如下: //hash+二分 #include <cstdio> #include <cstring> #include <algorithm> #include