zoukankan      html  css  js  c++  java
  • BZOJ3075[USACO 2013 Mar Gold 3.Necklace]——AC自动机+DP

    题目描述

    给你一个长度为n的字符串A,再给你一个长度为m的字符串B,求至少在A中删去多少个字符才能使得B不是A的子串。注:该题只读入A和B,不读入长度,先读入A,再读入B。数据保证A和B中只含小写字母。

    样例输入

    ababaa
    aba

    样例输出

    1

    样例解释:
    ababaa -> abbaa

    提示

    数据范围:
     n<=10000, m<=1000, m<=n

    据说这道题用KMP也能写

    首先如果用AC自动机做这道题显然要把B串建在AC自动机上(AC自动机上就一个串好像有点浪费qwq)。要想B串不出现在A串中,只要把A串在AC自动机上跑,使它一直不遍历到B串的终止节点就能保证B串不是A串的子串。想要最优解自然要dp,那么就可以定义f[i][j]表示A串的第i个字符匹配到了AC自动机上第j个节点保留的最长长度。对于A串上的每一个字符可以删除或者在AC自动机上往下走,最后用A串总长len减掉max{f[len][i]}就是最小删除数了。

    最后附上代码。

    #include<cmath>
    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    int cnt;
    char s[1010];
    char t[100010];
    int end[1010];
    int fail[1010];
    int a[1010][26];
    int f[10010][1010];
    void build(char *s)
    {
        int len=strlen(s);
        int now=0;
        for(int i=0;i<len;i++)
        {
            if(!a[now][s[i]-'a'])
            {
                a[now][s[i]-'a']=++cnt;
            }
            now=a[now][s[i]-'a'];
        }
        end[now]=1;
    }
    void getfail()
    {
        queue<int>q;
        for(int i=0;i<26;i++)
        {
            if(a[0][i])
            {
                q.push(a[0][i]);
                fail[a[0][i]]=0;
            }
        }
        while(!q.empty())
        {
            int now=q.front();
            q.pop();
            for(int i=0;i<26;i++)
            {
                if(a[now][i])
                {
                    fail[a[now][i]]=a[fail[now]][i];
                    q.push(a[now][i]);
                } 
                else
                {
                    a[now][i]=a[fail[now]][i];
                }
            }
        }
    }
    int main()
    {
        scanf("%s",t);
        scanf("%s",s);
        build(s);     
        getfail();
        memset(f,-1,sizeof(f));
        int l=strlen(t);
        f[1][0]=0;
        f[1][a[0][t[0]-'a']]=1;
        for(int i=1;i<l;i++)
        {
            for(int j=0;j<=cnt;j++)
            {
                if(f[i][j]!=-1)
                {
                    if(!end[a[j][t[i]-'a']])
                    {
                        f[i+1][a[j][t[i]-'a']]=max(f[i+1][a[j][t[i]-'a']],f[i][j]+1);
                    }
                    if(!end[j])
                    {
                        f[i+1][j]=max(f[i+1][j],f[i][j]);
                    }
                }
            }
        }
        int ans=0;
        for(int i=0;i<=cnt;i++)
        {
            if(!end[i]&&f[l][i]!=-1) 
            {
                ans=max(ans,f[l][i]);
            }
        }
        printf("%d",l-ans);
    }
  • 相关阅读:
    【bzoj1176】[Balkan2007]Mokia
    【bzoj1503】[NOI2004]郁闷的出纳员
    C#设置和获取系统环境变量
    结伙创业指南及翻脸法则
    Unity3D_(游戏)卡牌03_选关界面
    Unity3D_(游戏)卡牌02_主菜单界面
    Unity3D_(游戏)卡牌01_启动屏界面
    Unity3D_(游戏)跳一跳超简单制作过程
    如何将项目托管到Github上
    Android_(游戏)打飞机06:后续
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/9181960.html
Copyright © 2011-2022 走看看