zoukankan      html  css  js  c++  java
  • BZOJ_2099_[Usaco2010 Dec]Letter 恐吓信_后缀自动机+贪心

    BZOJ_2099_[Usaco2010 Dec]Letter 恐吓信_后缀自动机

    Description

    FJ刚刚和邻居发生了一场可怕的争吵,他咽不下这口气,决定佚名发给他的邻居 一封脏话连篇的信。他有无限张完全相同的已经打印好的信件,都包含 N个字母(1 <= N <= 50,000)。他想剪出其中一些并且粘帖成一个很长的字母串。 FJ太懒了,他想用最少的次数裁剪信件。他有一把举世无双的剪刀,他可以从 一封信中只剪一刀剪出连续一段。同样,剪一刀可以得到整个完整的字符串。 他想知道他最少需要剪多少刀从而获得这封M个字母的长信? 保证这总是可能的。 考虑下面38个字母的信: THEQUICKBROWNFOXDO GJUMPSOVERTHELAZYDOG 以及FJ想要获得的9个字母的信: FOXDOG DOG 以上是为了读入方便,实际上这两封信就是: THEQUICKBROWNFOXDOGJUMPSOVERTHELAZYDOG FOXDOGDOG 由于FOXDOG已经存在了,FJ可以剪一刀得到FOXDOG。还剩下一个DOG,FJ可以选择 其中任何一个DOG剪下来。 因此,他一共要剪2刀。

    Input

    * 第一行: 两个空格分隔的整数: N, M * 第2..?行: 一些行包含N个字母,FJ原来拥有的信,每行不会超过80个字母。 * 第?...?行: 一些行包含M个字母,FJ想要写的信,每行不会超过80个字母。

    Output

    * 第1行: FJ获得他想要写的信所需要切的最少次数。

    Sample Input

    38 9
    THEQUICKBROWNFOXDO
    GJUMPSOVERTHELAZYDOG
    FOXDOG
    DOG

    Sample Output

    2


    对第一个串建立后缀自动机,用第二个串去匹配。

    每次找最长的能匹配的子串即可。

    由于每次都选出一个子串,所以这个贪心是对的。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 50050
    using namespace std;
    inline char nc() {
        static char buf[100000],*p1,*p2;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    int ch[N<<1][26],dep[N<<1],fa[N<<1],cnt=1,lst=1,lw,ls;
    char w[N],s[N];
    void insert(int x) {
        int p=lst,np=++cnt,q,nq;
        lst=np; dep[np]=dep[p]+1;
        for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=np;
        if(!p) fa[np]=1;
        else {
            q=ch[p][x];
            if(dep[q]==dep[p]+1) fa[np]=q;
            else {
                fa[nq=++cnt]=fa[q];
                dep[nq]=dep[p]+1;
                memcpy(ch[nq],ch[q],sizeof(ch[q]));
                fa[q]=fa[np]=nq;
                for(;p&&ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
            }
        }
    }
    int main() {
        scanf("%d%d",&lw,&ls);
        int i,tot=0;
        while(1) {
            char c=nc(); while(c<'A'||c>'Z') c=nc();
            while(c>='A'&&c<='Z') w[++tot]=c,c=nc();
            if(tot==lw) break;
        }
        tot=0;
        while(1) {
            char c=nc(); while(c<'A'||c>'Z') c=nc();
            while(c>='A'&&c<='Z') s[++tot]=c,c=nc();
            if(tot==ls) break;
        }
        // printf("%s
    %s
    ",w+1,s+1);
        for(i=1;i<=lw;i++) insert(w[i]-'A');
        int ans=0,now=1,p;
        while(now<=ls) {
            p=1;
            while(ch[p][s[now]-'A']) p=ch[p][s[now]-'A'],now++;
            ans++;
        }
        printf("%d
    ",ans);
    }
    
  • 相关阅读:
    Linkerd 2.10(Step by Step)—将 GitOps 与 Linkerd 和 Argo CD 结合使用
    Linkerd 2.10(Step by Step)—多集群通信
    Linkerd 2.10(Step by Step)—使用 Kustomize 自定义 Linkerd 的配置
    Linkerd 2.10(Step by Step)—控制平面调试端点
    Linkerd 2.10(Step by Step)—配置超时
    Linkerd 2.10(Step by Step)—配置重试
    Linkerd 2.10(Step by Step)—配置代理并发
    本地正常运行,线上环境诡异异常原因集合
    Need to invoke method 'xxx' declared on target class 'yyy', but not found in any interface(s) of the exposed proxy type
    alpine 安装常用命令
  • 原文地址:https://www.cnblogs.com/suika/p/9148737.html
Copyright © 2011-2022 走看看