zoukankan      html  css  js  c++  java
  • 【Trie图+DP】BZOJ1030[JSOI2007]-文本生成器

    【题目大意】

    给出单词总数和固定的文章长度M,求出至少包含其中一个单词的可能文章数量。

    【思路】

    对于至少包含一个的类型,我们可以考虑补集。也就是等于[总的文章可能性总数-不包含任意一个单词的文章总数]有两个注意点:

    1.Trie图+DP。Trie图和AC自动机的区别在于,当孩子i为NULL时,则让孩子指针等于fail指针的孩子i,这样就可以继续匹配下去了。因此寻找fail指针的时候,可以不用循环而用判断语句即可。

    2.danger表示当前位置包含了单词,所以DP的时候舍去。如果你指向的fail指针是danger的,也就是你的后缀是danger的,那么当前的也是danger的。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<queue>
      6 using namespace std;
      7 const int MAXN=100+50;
      8 const int MAXM=60+5;
      9 const int MOD=10007; 
     10 const int NUMA=26;
     11 int n,m,cnt=0;
     12 struct ACauto
     13 {
     14     int id;
     15     int danger;
     16     ACauto* next[NUMA];
     17     ACauto* fail;
     18     ACauto()
     19     {
     20         danger=0;
     21         id=++cnt;
     22         for (int i=0;i<NUMA;i++) next[i]=NULL;
     23         fail=NULL;
     24     }
     25 };
     26 ACauto* node[MAXN*MAXM];
     27 int f[MAXN][MAXM*MAXN];
     28  
     29 void insert(ACauto* root,char* str)
     30 {
     31     int len=strlen(str);
     32     ACauto* tmp=root;
     33  
     34     for (int i=0;i<len;i++)
     35     {
     36         int index=str[i]-'A';
     37         if (tmp->next[index]==NULL)
     38         {
     39             tmp->next[index]=new ACauto;
     40             node[cnt]=tmp->next[index];
     41         }
     42         tmp=tmp->next[index];
     43     }
     44     tmp->danger=1;
     45 }
     46  
     47 void build(ACauto* root)
     48 {
     49     queue<ACauto*> que;
     50     que.push(root);
     51     while (!que.empty())
     52     {
     53         ACauto* head=que.front();que.pop();
     54         for (int i=0;i<NUMA;i++)
     55         {
     56             if (head->next[i]==NULL)
     57             {
     58                 if (head==root) head->next[i]=root;
     59                     else head->next[i]=head->fail->next[i];
     60             }
     61             else
     62             {
     63                 if (head==root) head->next[i]->fail=root;
     64                     else
     65                     {
     66                         head->next[i]->fail=head->fail->next[i];
     67                         if (head->next[i]->fail->danger) head->next[i]->danger=1;/*注意!*/
     68                     }
     69                 que.push(head->next[i]);
     70             }
     71         }
     72     }
     73 }
     74  
     75 void dp(ACauto* root)
     76 {
     77     memset(f,0,sizeof(f));
     78     f[0][1]=1;
     79     for (int i=0;i<=m-1;i++) 
     80         for (int j=1;j<=cnt;j++)
     81         {
     82             if (!node[j]->danger && f[i][j])
     83             {
     84                 for (int k=0;k<NUMA;k++)//枚举下一个字母
     85                     if (!node[j]->next[k]->danger) 
     86                         f[i+1][node[j]->next[k]->id]=(f[i][j]+f[i+1][node[j]->next[k]->id])%MOD;
     87             }
     88         }
     89 }
     90  
     91 void findres()
     92 {
     93     int ans1=0,ans2=1;
     94     for (int i=1;i<=cnt;i++)
     95         if (!node[i]->danger) ans1=(ans1+f[m][i])%MOD;
     96     for (int i=1;i<=m;i++) ans2=(ans2*NUMA)%MOD;
     97     cout<<(ans2-ans1+MOD)%MOD<<endl;
     98 }
     99  
    100 int main()
    101 {
    102     char str[MAXN];
    103     ACauto* root=new ACauto; 
    104     node[1]=root;
    105     scanf("%d%d",&n,&m);
    106     for (int i=0;i<n;i++)
    107     {
    108         scanf("%s",str);
    109         insert(root,str);
    110     }
    111  
    112      
    113     build(root);
    114     dp(root);
    115     findres();
    116     return 0;
    117 } 
  • 相关阅读:
    Java基础知识
    jQuery的表单操作
    SSM——查询_分页
    jQuery实现查看删除
    SSM之Maven工程的搭建
    Mybatis使用@Param
    Mybatis简单的CURD
    Mybatis使用接口开发
    初入Mybatis
    SQL语句
  • 原文地址:https://www.cnblogs.com/iiyiyi/p/5231286.html
Copyright © 2011-2022 走看看