• bzoj1030解题报告 tag:AC自动机+DP


      很开心在CNBLOG开通了博客,发布第一篇解题报告。借此机会,我也希望和广大的大神们交流学习。

      题意是给出N个可识别字符串和一个长度M。求在26M的这么多种字符串的可能性中找出有多少种字符串包含这N个字符串中的一个或多个,并把最终答案对10007取模。

      思路很容易想到是AC自动机+DP。

      f[d][i][j] (d=0..1, i=0..M, j=0..自动机状态数) 表示d表示当前状态取过没有,匹配到第i位,匹配到自动机的j状态所能得到的字符串数。

      动态转移方程:f[d|next[j]][i+1][next[j]] += f[d][i][j]

      最后统计∑f[1][M][i]。

      1 #include <cstdio>
      2 #include <cstdlib>
      3 #include <cstring>
      4 
      5 #define N 8000
      6 #define Module 10007
      7 
      8 using namespace std;
      9 
     10 struct node{
     11     int terminal, num;
     12     node* next[26];
     13     node* fail;
     14     node() { fail=NULL; terminal=0; memset(next,0,sizeof(next)); }
     15 } *root, *q[N];
     16 char st[N];
     17 int n, m, head, tail, f[2][103][N];
     18 
     19 void insert()
     20 {
     21     node* p=root;
     22     for (int i=0; st[i]; i++)
     23     {
     24         int index = st[i]-'A';
     25         if (p->next[index]==NULL) p->next[index] = new node();
     26         p = p->next[index];
     27     }
     28     p->terminal = 1;
     29 }
     30 
     31 void ac_auto()
     32 {
     33     head=-1, tail=0; q[0]=root;
     34     while (head<tail)
     35     {
     36         node *p = q[++head], *tmp;
     37         p->num = head;
     38         for (int i=0;i<26;i++)
     39             if (p->next[i]!=NULL)
     40             {
     41                 if (p==root) p->next[i]->fail = root;
     42                 else
     43                 {
     44                     tmp = p->fail;
     45                     while (tmp!=NULL)
     46                     {
     47                         if (tmp->next[i]!=NULL)
     48                         {
     49                             p->next[i]->fail = tmp->next[i];
     50                             break;
     51                         }
     52                         tmp = tmp->fail;
     53                     }
     54                     if (tmp==NULL) p->next[i]->fail = root;
     55                 }
     56                 if (p->next[i]->fail!=NULL && p->next[i]->fail->terminal) p->next[i]->terminal = 1;
     57                 q[++tail] = p->next[i];
     58             }
     59     }
     60 }
     61 
     62 void dp()
     63 {
     64     memset(f, 0, sizeof(f));
     65     f[0][0][0] = 1;
     66     for (int d=0;d<2;d++)
     67         for (int i=0;i<m;i++)
     68             for (int j=0;j<=head;j++)
     69                 if (f[d][i][j])
     70                 for (int k=0;k<26;k++)
     71                     {
     72                         node* p = q[j];
     73                         while (p && p->next[k]==NULL) p=p->fail;
     74                         if (p==NULL) p=root;
     75                         if (p->next[k]) p=p->next[k];
     76                         (f[d|p->terminal][i+1][p->num] += f[d][i][j]) %= Module;
     77                     }
     78     int ans = 0;
     79     for (int i=0;i<=head;i++)
     80         (ans += f[1][m][i]) %= Module;
     81     printf("%d
    ",ans);
     82 }
     83 
     84 int main()
     85 {
     86 #ifndef ONLINE_JUDGE
     87     freopen("bzoj1030.in","r",stdin);
     88     freopen("bzoj1030.out","w",stdout);
     89 #endif
     90     scanf("%d%d",&n,&m);
     91     root = new node();
     92     while (n--)
     93     {
     94         scanf("%s",st);
     95         insert();
     96     }
     97     ac_auto();
     98     dp();
     99     return 0;
    100 }

      一开始AC自动机写错了,DEBUG了一个晚上,还好还是DEBUG出来了。

      贴一组数据:

    bzoj1030.in
    
    8 3
    A
    BB
    CCC
    DDDD
    ZZZZZZ
    L
    N
    XDAFEW
    
    bzoj1030.out
    
    5455
  • 相关阅读:
    MyBatis笔记:xml映射文件
    MyBatis笔记:xml配置文件
    JSP获取当前系统时间并显示
    使用<jsp:forward>和<jsp:param>
    JSP简单总结
    网页版学生管理系统简易版DOM
    当为servlet配置时出现servlet标签报错
    给js的事件驱动函数添加快捷键
    js的表格对象和DOM联合操作
    Centos7安装Greenplum5.3单机版教程
  • 原文地址:https://www.cnblogs.com/africamonkey/p/3729991.html
Copyright © 2020-2023  润新知