• BZOJ 1030 [JSOI2007]文本生成器


    1030: [JSOI2007]文本生成器

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 2624  Solved: 1087
    [Submit][Status][Discuss]

    Description

    JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版。该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文章—— 也就是说,生成的文章中每个字节都是完全随机的。如果一篇文章中至少包含使用者们了解的一个单词,那么我们说这篇文章是可读的(我们称文章a包含单词b,当且仅当单词b是文章a的子串)。但是,即使按照这样的标准,使用者现在使用的GW文本生成器v6版所生成的文章也是几乎完全不可读的。 ZYX需要指出GW文本生成器 v6生成的所有文本中可读文本的数量,以便能够成功获得v7更新版。你能帮助他吗?

    Input

    输入文件的第一行包含两个正整数,分别是使用者了解的单词总数N (<= 60),GW文本生成器 v6生成的文本固定长度M;以下N行,每一行包含一个使用者了解的单词。 这里所有单词及文本的长度不会超过100,并且只可能包含英文大写字母A..Z  。

    Output

    一个整数,表示可能的文章总数。只需要知道结果模10007的值。

    Sample Input

    2 2
    A
    B

    Sample Output

    100

    HINT

     

    Source

    题解:acdp的入门题

    补集转换,变为求有danger的点的数量。一开始总是转不过弯来,现在懂了:窝萌设串前缀为考虑的阶段,那么在这个阶段要干什么呢?要"推进一步自动机"对不对,那么再加上一个维数表示考虑到了自动机上的节点就行了,具体实现的时候窝是直接写在了自动机里的f[m]。

    然后再说一下这个endmark,可以把ta想象成一个病毒,一开始在所有的end_node里,在窝萌getfail的时候,会顺着得到的fail指针传播,然后就没有然后了。。。具体实现就在getfail的时候维护一下就行。

    自动机还是一个挺神奇的东西,哪天补补PAM玩玩。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<stack>
     6 #include<queue>
     7 #include<cstring>
     8 #define PAU putchar(' ')
     9 #define ENT putchar('
    ')
    10 #define trans(p) while(p&&!p->tx[c])p=p->fail;if(!p)p=root;
    11 using namespace std;
    12 const int maxn=10000+10,maxnode=10000+10,sig=26,inf=-1u>>1,mod=10007;
    13 struct node{
    14     node*tx[sig],*fail;int f[110];bool v;node(){v=false;memset(f,0,sizeof(f));}
    15 }ac[maxnode],*nodecnt=ac,*root=nodecnt++;
    16 node*get(node*x){return x?x:root;}
    17 node*tran(node*x,int c){while(x&&!x->tx[c])x=x->fail;if(!x)x=root;return x;}
    18 void insert(char*s){
    19     node*x=root;
    20     for(int i=0;s[i];i++){
    21         int c=s[i]-'A';
    22         if(!x->tx[c])x->tx[c]=nodecnt++;
    23         x=x->tx[c];
    24     }x->v=true;return;
    25 }
    26 void getfail(){
    27     queue<node*>Q;for(int c=0;c<sig;c++)if(root->tx[c])Q.push(root->tx[c]);
    28     while(!Q.empty()){
    29         node*x=Q.front();Q.pop();
    30         for(int c=0;c<sig;c++)if(x->tx[c]){
    31             node*p=tran(x->fail,c);x->tx[c]->fail=get(p->tx[c]);
    32             if(p->tx[c]&&p->tx[c]->v)x->tx[c]->v=true;Q.push(x->tx[c]);
    33         }
    34     }return;
    35 }
    36 void dp(int x){
    37     for(node*t=ac;t!=nodecnt;t++){
    38         if(!t->v&&t->f[x-1])for(int c=0;c<sig;c++){
    39             node*p=tran(t,c);get(p->tx[c])->f[x]+=t->f[x-1]%=mod;
    40         }
    41     }return;
    42 }
    43 char s[maxn];int n,m;
    44 inline int read(){
    45     int x=0,sig=1;char ch=getchar();
    46     for(;!isdigit(ch);ch=getchar())if(ch=='-')sig=0;
    47     for(;isdigit(ch);ch=getchar())x=10*x+ch-'0';
    48     return sig?x:-x;
    49 }
    50 inline void write(int x){
    51     if(x==0){putchar('0');return;}if(x<0)putchar('-'),x=-x;
    52     int len=0,buf[15];while(x)buf[len++]=x%10,x/=10;
    53     for(int i=len-1;i>=0;i--)putchar(buf[i]+'0');return;
    54 }
    55 int main(){
    56     n=read();m=read();int ans=1,ans2=0;
    57     for(int i=1;i<=n;i++)scanf("%s",s),insert(s);
    58     getfail();root->f[0]=1;
    59     for(int i=1;i<=m;i++)dp(i),ans=ans*26%mod;
    60     for(node*t=ac;t!=nodecnt;t++)if(!t->v)(ans2+=t->f[m])%=mod;
    61     write((ans-ans2+mod)%mod);
    62     return 0;
    63 }
  • 相关阅读:
    🍖JS函数
    🍖JS流程控制
    🍖JS运算符介绍
    🍖JS数值类型与字符串类型的内置方法
    多态
    property装饰器
    封装
    组合
    继承&派生 属性查找
    继承与派生
  • 原文地址:https://www.cnblogs.com/chxer/p/4726697.html
Copyright © 2020-2023  润新知