• 洛谷 P4112 [HEOI2015]最短不公共子串 解题报告


    P4112 [HEOI2015]最短不公共子串

    题目描述

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

    一个串的“子串”指的是它的连续的一段,例如bcd是abcdef的子串,但bde不是。

    一个串的“子序列”指的是它的可以不连续的一段,例如bde是abcdef的子串,但bdd不是。

    下面,给两个小写字母串A,B,请你计算:

    (1) A的一个最短的子串,它不是B的子串

    (2) A的一个最短的子串,它不是B的子序列

    (3) A的一个最短的子序列,它不是B的子串

    (4) A的一个最短的子序列,它不是B的子序列

    输入输出格式

    输入格式:

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

    输出格式:

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

    说明

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

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

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


    四合一还行。

    问题1

    建立B的后缀自动机

    枚举A的开头,然后在B上从S向后跑,失配了更新答案

    问题2

    建立B的序列自动机

    然后一样的

    问题3

    在B的后缀自动机上跑DP(这样才能处理A的子序列)

    具体的(dp_i)表示这个点可以匹配上的最短长度

    从头开始枚举每个点更新。

    问题4

    在B的序列自动机上跑,其他和三一样

    数据太水,3,4的dp01背包写成完全背包也可以过...

    我3的dp写的是假的,懒得改了..


    Code:

    #include <cstdio>
    #include <cstring>
    const int N=4010;
    const int inf=0x3f3f3f3f;
    char s1[N],s2[N];
    int n,dp[N];
    int min(int x,int y){return x<y?x:y;}
    struct SuffixAutomata
    {
        int tot,las,len[N],ch[N][26],par[N];
        SuffixAutomata()
        {
            tot=las=1;
            memset(len,0,sizeof(len));
            memset(ch,0,sizeof(ch));
            memset(par,0,sizeof(par));
        }
        void extend(int c)
        {
            int now=++tot,p=las;
            len[now]=len[p]+1;
            while(p&&!ch[p][c]) ch[p][c]=now,p=par[p];
            if(!p) par[now]=1;
            else
            {
                int x=ch[p][c];
                if(len[x]==len[p]+1) par[now]=x;
                else
                {
                    int y=++tot;
                    len[y]=len[p]+1,par[y]=par[x];
                    memcpy(ch[y],ch[x],sizeof ch[y]);
                    while(p&&ch[p][c]==x) ch[p][c]=y,p=par[p];
                    par[now]=par[x]=y;
                }
            }
            las=now;
        }
        void build(char *s)
        {
            int n=strlen(s+1);
            for(int i=1;i<=n;i++) extend(s[i]-'a');
        }
    }T1;
    struct SequentialAutomaton
    {
        int suc[N],ch[N][26];
        SequentialAutomaton()
        {
            memset(suc,0,sizeof(suc));
            memset(ch,0,sizeof(ch));
        }
        void build(char *s)
        {
            int n=strlen(s+1);s[0]='a';
            for(int i=n;~i;i--)
            {
                for(int j=0;j<26;j++)
                    if(suc[j])
                        ch[i][j]=suc[j];
                suc[s[i]-'a']=i;
            }
        }
    }T2;
    void work1()
    {
        int ans=inf;
        for(int i=1;i<=n;i++)
        {
            int now=1;
            for(int j=i;j<=n;j++)
            {
                int c=s1[j]-'a';
                if(T1.ch[now][c]) now=T1.ch[now][c];
                else
                {
                    ans=min(ans,j+1-i);
                    break;
                }
            }
        }
        if(ans==inf) puts("-1");
        else printf("%d
    ",ans);
    }
    void work2()
    {
        int ans=inf;
        for(int i=1;i<=n;i++)
        {
            int now=0;
            for(int j=i;j<=n;j++)
            {
                int c=s1[j]-'a';
                if(T2.ch[now][c]) now=T2.ch[now][c];
                else
                {
                    ans=min(ans,j+1-i);
                    break;
                }
            }
        }
        if(ans==inf) puts("-1");
        else printf("%d
    ",ans);
    }
    void work3()
    {
        memset(dp,0x3f,sizeof dp);
        dp[1]=0;
        int ans=inf;
        for(int i=1;i<=n;i++)
        {
            int c=s1[i]-'a';
            for(int j=1;j<=T1.tot;j++)
            {
                int v=T1.ch[j][c];
                if(v) dp[v]=min(dp[v],dp[j]+1);
                else ans=min(ans,dp[j]+1);
            }
        }
        if(ans==inf) puts("-1");
        else printf("%d
    ",ans);
    }
    void work4()
    {
        memset(dp,0x3f,sizeof dp);
        dp[0]=0;
        int ans=inf;
        for(int i=1;i<=n;i++)
        {
            int c=s1[i]-'a';
            for(int j=n;~j;j--)
            {
                int v=T2.ch[j][c];
                if(v) dp[v]=min(dp[v],dp[j]+1);
                else ans=min(ans,dp[j]+1);
            }
        }
        if(ans==inf) puts("-1");
        else printf("%d
    ",ans);
    }
    int main()
    {
        scanf("%s%s",s1+1,s2+1);
        T1.build(s2),T2.build(s2),n=strlen(s1+1);
        work1(),work2(),work3(),work4();
        return 0;
    }
    

    2019.1.7

  • 相关阅读:
    轮播图
    .Net语言 APP开发平台——Smobiler学习日志:如何快速实现快递信息流的效果
    .Net语言 APP开发平台——Smobiler学习日志:如何实现离线声音文件上传
    .Net语言 APP开发平台——Smobiler学习日志:Poplist控件的正确打开方式以及如何快速实现
    .Net语言 APP开发平台——Smobiler学习日志:快速实现手机上的图片上传功能
    .Net语言 APP开发平台——Smobiler学习日志:快速在手机上实现n×m形式的菜单(IconMenuView)
    .Net语言 APP开发平台——Smobiler学习日志:快速在手机上实现日历功能
    .Net语言 APP开发平台——Smobiler学习日志:快速实现手机上常见的GridView
    .Net语言 APP开发平台——Smobiler学习日志:实现在手机上调用摄像头进行扫描
    .Net语言 APP开发平台——Smobiler学习日志:实现手机上常见的ListMenuView
  • 原文地址:https://www.cnblogs.com/butterflydew/p/10233113.html
Copyright © 2020-2023  润新知