• 字符串(后缀自动机):USACO Dec10 恐吓信


    【题目描述】

    FJ刚刚和邻居发生了一场可怕的争吵,他咽不下这口气,决定佚名发给他的邻居一封脏话连篇的信。他有无限张完全相同的已经打印好的信件,都包含 N个字母(1<=N<=50,000)。他想剪出其中一些并且粘帖成一个很长的字母串。

    FJ太懒了,他想用最少的次数裁剪信件。他有一把举世无双的剪刀,他可以从一封信中只剪一刀剪出连续一段。同样,剪一刀可以得到整个完整的字符串。

    他想知道他最少需要剪多少刀从而获得这封M1<=M<=50,000个字母的长信?

    保证这总是可能的。 

    考虑下面38个字母的信:
    THEQUICKBROWNFOXDO 

    GJUMPSOVERTHELAZYDOG 

    以及FJ想要获得的9个字母的信: 

    FOXDOG DOG 

    以上是为了读入方便,实际上这两封信就是: 

    THEQUICKBROWNFOXDOGJUMPSOVERTHELAZYDOG 

    FOXDOGDOG 

    由于FOXDOG已经存在了,FJ可以剪一刀得到FOXDOG。还剩下一个DOG,FJ可以选择其中任何一个DOG剪下来。

    因此,他一共要剪2刀。

    【输入格式】

    第1行: 两个空格分隔的整数: N,M  

    第2..?行: 一些行包含N个字母,FJ原来拥有的信,每行不会超过80个字母。  

    第?...?行: 一些行包含M个字母,FJ想要写的信,每行不会超过80个字母。

    【输出格式】

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

    【样例输入】

    38 9

    THEQUICKBROWNFOXDO

    GJUMPSOVERTHELAZYDOG

    FOXDOG

    DOG

    【样例输出】

    2

    【来源】

    J.Kuipers, 2002

      注意SAM要开两倍空间,不然死得惨……
      这里每次贪心地匹配最长的一段,失配后直接回rt即可,记得最后答案要加1,因为计数是失配一次才加一次。

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdio>
     4 using namespace std;
     5 const int maxn=100010;
     6 int read(){
     7     char c=getchar();
     8     while(c<'A'||c>'Z')
     9         c=getchar();
    10     return c-'A';    
    11 }
    12 int fa[maxn],len[maxn];
    13 int lst,cnt,ch[maxn][26];
    14 struct SAM{
    15     SAM(){cnt=lst=1;}
    16     void Insert(int c){
    17         int p=lst,np=lst=++cnt;len[np]=len[p]+1;
    18         while(p&&!ch[p][c])ch[p][c]=np,p=fa[p];
    19         if(!p)fa[np]=1;
    20         else{
    21             int q=ch[p][c],nq;
    22             if(len[q]==len[p]+1)
    23                 fa[np]=q;
    24             else{
    25                 nq=++cnt;len[nq]=len[p]+1;
    26                 memcpy(ch[nq],ch[q],sizeof(ch[q]));
    27                 fa[nq]=fa[q];fa[q]=fa[np]=nq;
    28                 while(ch[p][c]==q)ch[p][c]=nq,p=fa[p];
    29             }    
    30         }
    31     }
    32 }sam;
    33 int n,m;
    34 int main(){
    35     freopen("thre_letter.in","r",stdin);
    36     freopen("thre_letter.out","w",stdout);
    37     scanf("%d%d",&n,&m);
    38     for(int i=1;i<=n;i++)
    39         sam.Insert(read());
    40     int p=1,ans=0;
    41     for(int i=1;i<=m;i++){
    42         int c=read();
    43         if(!ch[p][c])
    44             {ans+=1;p=1;}
    45         p=ch[p][c];
    46     }    
    47     printf("%d
    ",ans+1);
    48     return 0;
    49 }
  • 相关阅读:
    <海量数据库解决方案>2011041201
    <海量数据库解决方案>2011040801
    <汇编语言(第2版)>2011041701
    makefile实践三为多目录源文件建立makefile
    <海量数据库解决方案>2011042501
    <海量数据库解决方案>2011041101
    <海量数据库解决方案>2011042901
    <海量数据库解决方案>2011042601
    <海量数据库解决方案>2011050301
    <iPhone开发秘籍>温度转换器实践
  • 原文地址:https://www.cnblogs.com/TenderRun/p/5707870.html
Copyright © 2020-2023  润新知