BZOJ 4032: [HEOI2015]最短不公共子串 后缀自动机 暴力

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

题目连接:

http://www.lydsy.com/JudgeOnline/problem.php?id=4032

Description

在虐各种最长公共子串、子序列的题虐的不耐烦了之后,你决定反其道而行之。

一个串的“子串”指的是它的连续的一段,例如bcd是abcdef的子串,但bde不是。
一个串的“子序列”指的是它的可以不连续的一段,例如bde是abcdef的子串,但bdd不是。
下面,给两个小写字母串A,B,请你计算:
(1) A的一个最短的子串,它不是B的子串
(2) A的一个最短的子串,它不是B的子序列
(3) A的一个最短的子序列,它不是B的子串
(4) A的一个最短的子序列,它不是B的子序列

Input

有两行,每行一个小写字母组成的字符串,分别代表A和B。

Output

输出4行,每行一个整数,表示以上4个问题的答案的长度。如果没有符合要求的答案,输出-1.

Sample Input

aabbcc

abcabc

Sample Output

2

4

2

4

Hint

对于100%的数据,A和B的长度都不超过2000

题意

题解:

bfs四合一

答案都是最长公共子XX+1

子串我们用后缀自动机去跑,子序列我们用dp的贪心去跑就好了

那个dp表示从i位置走到字符j的最小位置

注意后缀自动机要开两倍空间……因为这个,wa成傻逼了

代码

#include<bits/stdc++.h>
using namespace std;

const int maxn = 2e3+5;
char s1[maxn],s2[maxn];
int len1,len2;
int go1[maxn][26],go2[maxn][26];
int vis[maxn][maxn*2];
int Son[maxn*2][26],pre[maxn*2],len[maxn*2],la=1,Now=1;
struct SAM
{
    void add(int x)
    {
        int p=la,np=la=++Now;
        len[np]=len[p]+1;
        for(;p&&!Son[p][x];p=pre[p])
            Son[p][x]=np;
        if(!p)
            pre[np]=1;
        else
        {
            int q=Son[p][x];
            if(len[q]==len[p]+1)
                pre[np]=q;
            else
            {
                int nq=++Now;
                memcpy(Son[nq],Son[q],sizeof Son[nq]);
                len[nq]=len[p]+1;
                pre[nq]=pre[q];
                pre[q]=pre[np]=nq;
                for(;p&&Son[p][x]==q;p=pre[p])
                    Son[p][x]=nq;
            }
        }
    }
}sam;

struct node
{
    int x,y,l;
};
queue<node>Q;
void init()
{
    memset(vis,0,sizeof(vis));
    while(!Q.empty())Q.pop();
}
int solve1()
{
    init();
    for(int i=0;i<len1;i++)
        Q.push(node{i,1,0});
    while(!Q.empty())
    {
        node Now = Q.front();
        Q.pop();
        if(Now.x==len1)continue;
        int nextx=Now.x+1,nexty=Son[Now.y][s1[nextx]-'a'];
        if(nexty==0)return Now.l+1;
        if(!vis[nextx][nexty])
            vis[nextx][nexty]=1,Q.push(node{nextx,nexty,Now.l+1});
    }
    return -1;
}
int solve2()
{
    init();
    for(int i=0;i<len1;i++)
        Q.push(node{i,0,0});
    while(!Q.empty())
    {
        node Now = Q.front();
        Q.pop();
        if(Now.x==len1)continue;
        int nextx=Now.x+1,nexty=go2[Now.y][s1[Now.x+1]-'a'];
        if(nexty==1e5)return Now.l+1;
        if(!vis[nextx][nexty])
            vis[nextx][nexty]=1,Q.push(node{nextx,nexty,Now.l+1});
    }
    return -1;
}
int solve3()
{
    init();
    Q.push(node{0,1,0});
    while(!Q.empty())
    {
        node Now = Q.front();
        Q.pop();
        for(int i=0;i<26;i++)
        {
            int nextx=go1[Now.x][i],nexty=Son[Now.y][s1[nextx]-'a'];
            if(nextx==1e5)continue;
            if(nexty==0)return Now.l+1;
            if(!vis[nextx][nexty])
            vis[nextx][nexty]=1,Q.push(node{nextx,nexty,Now.l+1});
        }
    }
    return -1;
}
int solve4()
{
    init();
    Q.push(node{0,0,0});
    while(!Q.empty())
    {
        node Now = Q.front();
        Q.pop();
        for(int i=0;i<26;i++)
        {
            int nextx=go1[Now.x][i],nexty=go2[Now.y][i];
            if(nextx==1e5)continue;
            if(nexty==1e5)return Now.l+1;
            if(!vis[nextx][nexty])
            vis[nextx][nexty]=1,Q.push(node{nextx,nexty,Now.l+1});
        }
    }
    return -1;
}
int main()
{
    scanf("%s%s",s1+1,s2+1);
    len1=strlen(s1+1),len2=strlen(s2+1);
    for(int i=1;i<=len2;i++)sam.add(s2[i]-'a');
    for(int i=0;i<maxn;i++)for(int j=0;j<26;j++)
        go1[i][j]=go2[i][j]=1e5;
    for(int i=0;i<=len1;i++)
        for(int j=i+1;j<=len1;j++)
            go1[i][s1[j]-'a']=min(go1[i][s1[j]-'a'],j);
    for(int i=0;i<=len2;i++)
        for(int j=i+1;j<=len2;j++)
            go2[i][s2[j]-'a']=min(go2[i][s2[j]-'a'],j);
    printf("%d\n%d\n%d\n%d\n",solve1(),solve2(),solve3(),solve4());
}
posted @ 2016-02-21 13:13  qscqesze  阅读(657)  评论(0编辑  收藏  举报