zoukankan      html  css  js  c++  java
  • bzoj 1030 [JSOI2007]文本生成器(AC自动机+DP)

    【题目链接】

      http://www.lydsy.com/JudgeOnline/problem.php?id=1030

    【题意】

      给n个小串,随机构造一个长为m的大串,一个串合法当且仅当包含一个或多个给定的小串,问合法串的数目。

    【思路】

          

       AC自动机+DP

         首先将问题转化为求不合法的大串的数目。

           将所有单词加入AC自动机,让f[i][j]表示长度为i的文章结尾为自动机中的j号节点的不经过单词节点的方案总数(呼~),就是在自动机上找一条不经过单词节点的路径,DP统计。然后用总方案数26^m减去sigma{f[m][i] , 0<=i<sz且val[i]==0}

           注意如果后缀是一个单词节点则该节点也要标记为单词节点。

    【代码】

     1 #include<cstdio>
     2 #include<queue>
     3 #include<cstring>
     4 #include<iostream>
     5 using namespace std;
     6 
     7 const int N=60+5,L=100+5;
     8 const int node = N*L,MOD=1e4+7;
     9 const int sigma = 26;
    10 
    11 struct ACauto{
    12     int ch[node][sigma],f[node],val[node],sz;
    13     void clear() {
    14         sz=1; memset(ch[0],0,sizeof(ch[0]));
    15     }
    16     void insert(char *s) {
    17         int n=strlen(s),u=0;
    18         for(int i=0;i<n;i++) {
    19             int c=s[i]-'A';
    20             if(!ch[u][c]) {
    21                 memset(ch[sz],0,sizeof(ch[sz]));
    22                 val[sz]=0; ch[u][c]=sz++;
    23             }
    24             u=ch[u][c];
    25         }
    26         val[u]=1;
    27     }
    28     void get_Fail() {
    29         queue<int> q;
    30         f[0]=0;
    31         for(int c=0;c<sigma;c++) 
    32             if(ch[0][c]) f[ch[0][c]]=0,q.push(ch[0][c]);
    33         while(!q.empty()) {
    34             int r=q.front(); q.pop();
    35             for(int c=0;c<sigma;c++) {
    36                 int u=ch[r][c]; if(!u) continue;
    37                 q.push(u);  int v=f[r];
    38                 while(v&&!ch[v][c]) v=f[v];
    39                 if(val[ch[v][c]]) val[u]=1;
    40                 f[u]=ch[v][c];
    41             }
    42         }
    43      }
    44 }ac;
    45 
    46 char s[L]; int n,m; int d[L][node];
    47 
    48 int main() {
    49     scanf("%d%d",&n,&m);
    50     ac.clear();
    51     for(int i=0;i<n;i++) {
    52         scanf("%s",s); ac.insert(s);
    53     }
    54     ac.get_Fail();
    55     d[0][0]=1;
    56     for(int i=1;i<=m;i++)
    57         for(int j=0;j<ac.sz;j++) if(!ac.val[j]&&d[i-1][j]) {
    58             for(int c=0;c<sigma;c++) {
    59                 int k=j; while(!ac.ch[k][c]&&k) k=ac.f[k];
    60                 d[i][ac.ch[k][c]]=(d[i-1][j]+d[i][ac.ch[k][c]])%MOD;
    61             }
    62         }
    63     int ans1=0,ans2=1;
    64     for(int i=1;i<=m;i++) ans2=(ans2*26)%MOD;
    65     for(int i=0;i<ac.sz;i++)
    66         if(!ac.val[i]) ans1=(ans1+d[m][i])%MOD;
    67     printf("%d",(ans2-ans1+MOD)%MOD);
    68     return 0;
    69 }
  • 相关阅读:
    form和button和input
    onmouseover和onfocus和select一起完成的操作
    事件和事件句柄的理解
    onunload对应的js代码为什么不能执行?和onbeforeunload的区别?
    表单及其控件的了解
    表单及其控件的访问
    【JAVA SE基础篇】59.同步块、并发容器和死锁
    【JAVA SE基础篇】58.线程并发的非同步、同步与锁机制
    【JAVA SE基础篇】57.线程礼让、插队、优先调用、守护线程与其他
    【JAVA SE基础篇】56.线程状态、方法
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5195761.html
Copyright © 2011-2022 走看看