图片加载可能有点慢,请跳过题面先看题解,谢谢


一看到这么多模式串就非常兴奋,又是\(AC\)自动机
题目就是要求:经过 \(n\) 个节点,把所有单词都遍历一遍的方案数,和那道题差不多嘛
所以这样设:\(f[i][j][k]\) 为,走了 \(i\) 个节点,当前点在 \(j\),单词的经过情况为 \(k\)(一个二进制数)时的方案数
答案很显然是:\(\sum_{i=1}^{size}f[n][i][(1<<m)-1]\)
转移也很显然:\(f[i+1][Son][s|val[Son]]+=f[i][j][s]\)
$
$
但是这道题有点麻烦的就是,它需要输出方案,上面那样子做不太好记录路径
这里考虑反过来搞,这样转移:\(f[i][j][s]+=f[i+1][Son][s|val[Son]]\),答案就变成了\(f[0][0][0]\)
这样做的话,就可以保证只有在有效路径上,\(f\) 值才不为\(0\),那么方案就很好办了
$
$

//made by Hero_of_Someone
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<set>
#define ll long long
using namespace std;

int t,n,m;

struct Trie{
   char o[26];
   int root,size;
   ll f[26][110][1<<10];
   int son[110][30],fail[110],val[110];

   void init(){
      size=1; root=0;
      memset(son,0,sizeof(son));
      memset(val,0,sizeof(val));
      memset(fail,0,sizeof(fail));
      memset(f[n],0,sizeof(f[n]));
   }

   int idx(char c){ return c-'a'; }

   void insert(char* s,int v){
      int cur=root;
      for(int i=0;s[i];i++){
         int id=idx(s[i]);
         if(!son[cur][id]) son[cur][id]=size++;
         cur=son[cur][id];
      }
      val[cur]|=1<<v; return ;
   }

   void build(){
      int que[110];
      int hd=0,tl=0;
      for(int i=0;i<26;i++)
         if(son[root][i]){
            fail[son[root][i]]=root;
            que[tl++]=son[root][i];
         }
         else son[root][i]=root;

      while(hd<tl){
         int cur=que[hd++];
         for(int i=0;i<26;i++){
            int Son=son[cur][i];
            if(Son){
               int f=fail[cur];
               while(f && !son[f][i]) f=fail[f];
               fail[Son]=son[f][i];
               val[Son]|=val[fail[Son]];
               que[tl++]=Son;
            }
            else son[cur][i]=son[fail[cur]][i];
         }
      }
   }

   ll dp(){
      for(int i=0;i<size;i++) f[n][i][(1<<m)-1]=1;
      for(int i=n-1;i>=0;i--)
         for(int j=0;j<size;j++)
            for(int s=0;s<(1<<m);s++){
               f[i][j][s]=0;
               for(int k=0;k<26;k++){
                  int Son=son[j][k];
                  int ss=s|val[Son];
                  f[i][j][s]+=f[i+1][Son][ss];
               }
            }
      return f[0][0][0];
   }

   void print(int i,int j,int s){
      if(i==n){
         for(int k=0;k<n;k++) printf("%c",o[k]);
         puts("");
         return ;
      }
      for(int k=0;k<26;k++){
         int Son=son[j][k];
         int ss=s|val[Son];
         if(f[i+1][Son][ss]){
            o[i]=k+'a';
            print(i+1,Son,ss);
         }
      }
   }

}AC;

set<string>map;

void init(){
   AC.init(),map.clear();
   int cnt=0;
   for(int i=0;i<m;i++){
      char s[15];
      scanf("%s",s);
      string S=s;
      if(!map.count(S)){
         AC.insert(s,cnt++);
         map.insert(S);
      }
   }
   m=cnt;
}

void work(){
   AC.build();
   ll ans=AC.dp();
   printf("Case %d: %lld suspects\n",++t,ans);
   if(ans<=42) AC.print(0,0,0);
}

int main(){ while(scanf("%d%d",&n,&m)&&n){ init(); work(); } return 0; }

沉迷AC自动机无法自拔之:[UVALive 4126] Password Suspects的更多相关文章

  1. 沉迷AC自动机无法自拔之:[BZOJ2434] [Noi2011] 阿狸的打字机

    如标题所言,我已经沉迷于AC自动机无法自拔了... 这又是一道AC自动的题,红红火火恍恍惚惚 这题目做起来真舒服 简单概括一下:\(AC\)自动机\(fail\)树上树链剖分\(+\)树状数组 这种类 ...

  2. 沉迷AC自动机无法自拔之:穿越广场 square

    如标题所言,我已经沉迷于AC自动机无法自拔了... 这又是一道AC自动的题,红红火火恍恍惚惚 穿越广场 [问题描述] L 国的仪仗队要穿越首都广场了.首都广场可以看做是一块 N*M 的矩形网格,仪仗队 ...

  3. 沉迷AC自动机无法自拔之:[UVA 11468] Substring

    图片加载可能有点慢,请跳过题面先看题解,谢谢 这个鬼题目,上一波套路好了 先用题目给的模板串建\(AC\)自动机,把单词结尾标记为 \(val=1\),然后在建好的\(AC\)自动机上跑 \(dp\) ...

  4. UVALive - 4126 Password Suspects (AC自动机+状压dp)

    给你m个字符串,让你构造一个字符串,包含所有的m个子串,问有多少种构造方法.如果答案不超过42,则按字典序输出所有可行解. 由于m很小,所以可以考虑状压. 首先对全部m个子串构造出AC自动机,每个节点 ...

  5. LA 4126 Password Suspects

    问题描述:给定m个模式串,计数包含所有模式串且长度为n的字符串的数目. 数据范围:模式串长度不超过10,m <= 10, n <= 25,此外保证答案不超过1015. 分析:既然要计数给定 ...

  6. DP(记忆化搜索) + AC自动机 LA 4126 Password Suspects

    题目传送门 题意:训练指南P250 分析:DFS记忆化搜索,范围或者说是图是已知的字串构成的自动机图,那么用 | (1 << i)表示包含第i个字串,如果长度为len,且st == (1 ...

  7. UVALive 4670 Dominating Patterns --AC自动机第一题

    题意:多个模板串,一个文本串,求出那些模板串在文本串中出现次数最多. 解法:AC自动机入门模板题. 代码: #include <iostream> #include <cstdio& ...

  8. UVALive - 3490 Generator (AC自动机+高斯消元dp)

    初始有一个空串s,从前n个大写字母中不断随机取出一个字母添加到s的结尾,出现模式串t时停止,求停止时s的长度期望. 这道题解法不唯一,比较无脑的方法是对模式串t建一个单串AC自动机,设u为自动机上的一 ...

  9. UVALive 4670 Dominating Patterns (AC自动机)

    AC自动机的裸题.学了kmp和Trie以后不难看懂. 有一些变化,比如0的定义和f的指向,和建立失配边,以及多了后缀连接数组last.没有试过把失配边直接当成普通边(一开始还是先这样写吧). #inc ...

随机推荐

  1. JS设置cookie、读取cookie、删除cookie(转载)

    JavaScript是运行在客户端的脚本,因此一般是不能够设置Session的,因为Session是运行在服务器端的.而cookie是运行在客户端的,所以可以用JS来设置cookie.假设有这样一种情 ...

  2. C++面向对象模型

    1. 基础知识 C++编译器怎样完毕面向对象理论到计算机程序的转化? 换句话:C++编译器是怎样管理类.对象.类和对象之间的关系 详细的说:详细对象调用类写的方法,那,c++编译器是怎样区分,是那个详 ...

  3. MB_SELECT_GR_BLOCKED_STOCK 读取物料收货冻结库存

    MMBE 查询物料的当前库存,有一列是收货冻结库存(GR Blocked Stock),但是没有明细. 通过函数 MB_SELECT_GR_BLOCKED_STOCK 可以查询物料收货冻结库存的明细. ...

  4. Pick定理、欧拉公式和圆的反演

    Pick定理.欧拉公式和圆的反演 Tags:高级算法 Pick定理 内容 定点都是整点的多边形,内部整点数为\(innod\),边界整点数\(ednod\),\(S=innod+\frac{ednod ...

  5. Centos7下python3安装pip-9.0.1

    pip类似RedHat里面的yum,安装Python包非常方便.本节详细介绍pip的安装.以及使用方法 1.下载pip安装包 [root@localhost ~]# wget https://pypi ...

  6. HTML5 之 FileReader 方法上传并读取文件

    原文地址:https://caochangkui.github.io/file-upload/ HTML5 的 FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据 ...

  7. PHP调用WCF提供的方法

    一.准备工作 1.安装wampserver:过程略 2.配置wampserver: 2.1打开php.ini文件,去掉 ;extension=php_soap.dll 这里那个分号. 也有说把这个 ; ...

  8. Elasticsearch Query DSL 整理总结(一)—— Query DSL 概要,MatchAllQuery,全文查询简述

    目录 引言 概要 Query and filter context Match All Query 全文查询 Full text queries 小结 参考文档 引言 虽然之前做过 elasticse ...

  9. python数据图形化—— matplotlib 基础应用

    matplotlib是python中常用的数据图形化工具,用法跟matlab有点相似.调用简单,功能强大.在Windows下可以通过命令行 pip install matplotlib 来进行安装. ...

  10. 二叉树 c++

    树 非空树 有一个(root)根节点r 其余节点可分为m个互不相交的有限集(子树)T1....Tm 具有n个节点的树,具有(n-1)条连接(指针域),需要构成结构体,尽可能减少空间域的浪费,使用儿子兄 ...