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

题目传送门

题意:训练指南P250

分析:DFS记忆化搜索,范围或者说是图是已知的字串构成的自动机图,那么用 | (1 << i)表示包含第i个字串,如果长度为len,且st == (1 << m) - 1则是可能的。打印与之前相似。

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 25 + 5;
const int NODE = 10 * 10 + 5;
const int M = (1 << 10) + 5;
const int SIZE = 26;

int n, m;
char str[12];
struct AC   {
    int ch[NODE][SIZE], val[NODE], fail[NODE], last[NODE], sz;
    ll dp[NODE][N][M];  int out[N];
    void clear(void)    {
        memset (ch[0], 0, sizeof (ch[0]));
        sz = 1;
    }
    int idx(char c) {
        return c - ‘a‘;
    }
    void insert(char *s, int v)   {
        int u = 0;
        for (int c, i=0; s[i]; ++i)    {
            c = idx (s[i]);
            if (!ch[u][c])  {
                memset (ch[sz], 0, sizeof (ch[sz]));
                val[sz] = 0;
                ch[u][c] = sz++;
            }
            u = ch[u][c];
        }
        val[u] |= (1 << v);
    }
    void build(void) {
        queue<int> que; fail[0] = 0;
        for (int c=0; c<SIZE; ++c)  {
            int u = ch[0][c];
            if (u)  {
                fail[u] = 0;    last[u] = 0;
                que.push (u);
            }
        }
        while (!que.empty ())   {
            int r = que.front ();   que.pop ();
            for (int c=0; c<SIZE; ++c)  {
                int &u = ch[r][c];
                if (!u) {
                    u = ch[fail[r]][c]; continue;
                }
                que.push (u);
                int v = fail[r];
                while (v && !ch[v][c])  v = fail[v];
                fail[u] = ch[v][c];
                val[u] |= val[fail[u]];
                //last[u] = val[fail[u]] ? fail[u] : last[fail[u]];
            }
        }
    }
    void print(int now, int len, int st)    {
        if (len == n)   {
            for (int i=0; i<len; ++i)   {
                printf ("%c", out[i] + ‘a‘);
            }
            puts ("");  return ;
        }
        for (int c=0; c<SIZE; ++c)  {
            if (dp[ch[now][c]][len+1][st|val[ch[now][c]]] > 0)   {
                out[len] = c;
                print (ch[now][c], len + 1, st | val[ch[now][c]]);
            }
        }
    }
    ll DP(int now, int len, int st)   {
        ll &ans = dp[now][len][st];
        if (ans != -1) return ans;
        if (len == n)   {
            if (st == (1 << m) - 1) return ans = 1;
            else    return ans = 0;
        }
        ans = 0;
        for (int c=0; c<SIZE; ++c)  {
            ans += DP (ch[now][c], len + 1, st | val[ch[now][c]]);
        }
        return ans;
    }
    void run(void)  {
        memset (dp, -1, sizeof (dp));
        ll ans = DP (0, 0, 0);
        printf ("%lld suspects\n", ans);
        if (ans <= 42)  {
            print (0, 0, 0);
        }
    }
}ac;

int main(void)  {
    int cas = 0;
    while (scanf ("%d%d", &n, &m) == 2) {
        if (!n && !m)   break;
        ac.clear ();
        for (int i=0; i<m; ++i) {
            scanf ("%s", &str);
            ac.insert (str, i);
        }
        ac.build ();
        printf ("Case %d: ", ++cas);
        ac.run ();
    }

    return 0;
}

  

时间: 2024-10-08 03:16:04

DP(记忆化搜索) + AC自动机 LA 4126 Password Suspects的相关文章

UVA 11468 Substring (记忆化搜索 + AC自动鸡)

传送门 题意: 给你K个模式串, 然后,再给你 n 个字符, 和它们出现的概率 p[ i ], 模式串肯定由给定的字符组成. 且所有字符,要么是数字,要么是大小写字母. 问你生成一个长度为L的串,不包含任何模式串的概率是多少. 解: 记忆化搜索 +  AC自动机. 对模式串建一个AC自动机, 不需要last[ ] 和 val[ ], 只需要一个 metch[ ]. 维护一下这个点是否是某个模式串的最后一个字符节点,若是,则这个点不能走. 然后, 剩下的就是从根节点,随便走 L 步, 记得要记忆化

11782 - Optimal Cut(树形DP+记忆化搜索)

题目链接:11782 - Optimal Cut 题意:按前序遍历给定一棵满二叉树,现在有k次,可以选k个节点,获得他们的权值,有两个条件: 1.一个节点被选了,他的子节点就不能选了. 2.最终选完后,根到所有叶子的路径上,都要有一个被选的节点. 思路:树形dp,dp[u][k]代表在结点u,可以选k个节点,那么就分两种情况 选u节点,dp[u][k] = node[u]; 选子节点之和,那么就把k次分配给左右孩子,dp[u][k] = max(dp[u][k], dp[u][i], dp[u]

[hihocoder 1033]交错和 数位dp/记忆化搜索

#1033 : 交错和 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个数 x,设它十进制展从高位到低位上的数位依次是 a0,?a1,?...,?an?-?1,定义交错和函数: f(x)?=?a0?-?a1?+?a2?-?...?+?(?-?1)n?-?1an?-?1 例如: f(3214567)?=?3?-?2?+?1?-?4?+?5?-?6?+?7?=?4 给定 输入 输入数据仅一行包含三个整数,l,?r,?k(0?≤?l?≤?r?≤?1018,?|k|

UVA - 10817 Headmaster&#39;s Headache (状压dp+记忆化搜索)

题意:有M个已聘教师,N个候选老师,S个科目,已知每个老师的雇佣费和可教科目,已聘老师必须雇佣,要求每个科目至少两个老师教的情况下,最少的雇佣费用. 分析: 1.为让雇佣费尽可能少,雇佣的老师应教他所能教的所有科目. 2.已聘老师必须选,候选老师可选可不选. 3.dfs(cur, subject1, subject2)---求出在当前已选cur个老师,有一个老师教的科目状态为 subject1,有两个及以上老师教的科目状态为 subject2的情况下,最少的雇佣费用. dp[cur][subje

UVa 10817 (状压DP + 记忆化搜索) Headmaster&#39;s Headache

题意: 一共有s(s ≤ 8)门课程,有m个在职教师,n个求职教师. 每个教师有各自的工资要求,还有他能教授的课程,可以是一门或者多门. 要求在职教师不能辞退,问如何录用应聘者,才能使得每门课只少有两个老师教而且使得总工资最少. 分析: 因为s很小,所以可以用状态压缩. dp(i, s1, s2)表示考虑了前i个人,有一个人教的课程的集合为s1,至少有两个人教的集合为s2. 在递归的过程中,还有个参数s0,表示还没有人教的科目的集合. 其中m0, m1, s0, s1, s2的计算用到位运算,还

poj1664 dp记忆化搜索

http://poj.org/problem?id=1664 Description 把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法. Input 第一行是测试数据的数目t(0 <= t <= 20).以下每行均包含二个整数M和N,以空格分开.1<=M,N<=10. Output 对输入的每组数据M和N,用一行输出相应的K. Sample Input 1 7 3 Sample Output 8 /

【DP】树形DP 记忆化搜索

DP中的树形DP,解决方法往往是记忆化搜索.显然,树上递推是很困难的.当然做得时候还是得把状态定义和转移方程写出来:dp[u][1/0]表示以u为根节点的树 涂(1) 或 不涂(0) 颜色的最少方案数.树上DP有两个经典问法:一条边两端至少有个一个端点涂色,问整个tree最少涂色次数:还有一种忘了...此题是前种问法. #include<cstdio> #include<cstring> #include<algorithm> using namespace std;

POJ 4968 DP||记忆化搜索

给出N个人的平局分X 根据GPA规则计算可能的最高平均GPA和最低平均GPA 可以DP预处理出来所有结果  或者记忆化搜索 DP: #include "stdio.h" #include "string.h" int inf=100000000; double a[11][1100],b[11][1100]; double Max(double a,double b) { if (a<b) return b; else return a; } double M

状压DP+记忆化搜索 UVA 1252 Twenty Questions

题目传送门 1 /* 2 题意:给出一系列的01字符串,问最少要问几个问题(列)能把它们区分出来 3 状态DP+记忆化搜索:dp[s1][s2]表示问题集合为s1.答案对错集合为s2时,还要问几次才能区分出来 4 若和答案(自己拟定)相差小于等于1时,证说明已经能区分了,回溯.否则还要加问题再询问 5 */ 6 /************************************************ 7 * Author :Running_Time 8 * Created Time :