[JSOI2009]密码 [AC自动机]
题面
首先看到这题就知道随便暴枚
只要是多项式算法都能过
先常规建AC自动机
注意被别的单词包含的单词没有存在的价值
剩余单词状压
大力dp f[长度][节点编号][状态]
\(ans = \sum f[m][i][S]\)
这里把题面的l换成m了 表示密码长度
如果方案数小于等于42的话
说明这个密码是给定词拼成的 不会有自由字母
那么就逆向找到转移到它的状态 记录密码就好啦
注意比较那里原来写的是
if(x.s[i] > y.s[i]) return 1;
显然这样是不行的啊qvq
#include <cmath>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <complex>
#include <ctime>
#include <vector>
#include <queue>
#include <bitset>
#define mp(x, y) make_pair(x, y)
using namespace std;
const int N = 12;
const int M = 102;
const int Sig = 26;
int m, n, acsize, vsize, S;
int en[N], c[M], val[M];
long long ans, f[26][M][(1 << 10) + 5];
struct STR{
    char s[30];
    void print(){s[m + 1] = '\0'; printf("%s\n", s + 1);}
    friend bool operator <(STR x, STR y){
        for(int i = 1; i <= m; ++i)
            if(x.s[i] != y.s[i]) return x.s[i] > y.s[i];
        return 0;
    }//大于
}stk;
vector<STR> str;
struct AC{
    int ch[M][Sig], fail[M];
    queue<int> que;
    void ins(char* ss, int id){
        int now = 0, len = strlen(ss + 1);
        for(int i = 1, cc; i <= len; ++i){
            cc = ss[i] - 'a';
            if(!ch[now][cc]) ch[now][cc] = ++acsize;
            now = ch[now][cc]; c[now] = cc;
        }
        en[id] = now, val[now] = 1;
    }
    void build(){
        int now = 0;
        for(int i = 0; i < Sig; ++i) if(ch[0][i]) que.push(ch[0][i]);
        while(!que.empty()){
            int fro = que.front(); que.pop();
            for(int i = 0; i < Sig; ++i){
                if(ch[fro][i]) fail[ch[fro][i]] = ch[fail[fro]][i], que.push(ch[fro][i]);//!!
                else ch[fro][i] = ch[fail[fro]][i];
            }
        }
        for(int i = 0; i <= acsize; ++i) val[fail[i]] = 0;
        for(int i = 0; i <= acsize; ++i) if(val[i])
            val[i] = (1 << vsize), ++vsize;
        S = (1 << vsize) - 1;
    }
    void DP(){
        f[0][0][0] = 1;
        for(int i = 0; i < m; ++i)
            for(int j = 0; j <= acsize; ++j)
                for(int k = 0; k <= S; ++k) if(f[i][j][k]){
        for(int t = 0; t < Sig; ++t){
            f[i + 1][ch[j][t]][k | val[ch[j][t]]] += f[i][j][k];
              //  printf("%d %d %d %lld\n", i, j, k, f[i + 1][ch[j][t]][k | val[ch[j][t]]]);
        }
                }
    }
}ac;
void dfs(int x, int cur, int y, int z){
    stk.s[x] = z + 'a';
    if(x == 1){str.push_back(stk); return ;}
    for(int i = 0; i <= acsize; ++i)
        if(f[x - 1][i][y] > 0 && ac.ch[i][z] == cur)
            dfs(x - 1, i, y, c[i]);
    if(val[cur])
        for(int i = 0; i <= acsize; ++i)
            if(f[x - 1][i][y ^ val[cur]] > 0 && ac.ch[i][z] == cur)
                dfs(x - 1, i, y ^ val[cur], c[i]);
}
int main(){
    scanf("%d%d", &m, &n);
    char ss[N];
    for(int i = 1; i <= n; ++i){
        scanf("%s", ss + 1);
        ac.ins(ss, i);
    }
    ac.build();
    ac.DP();
    for(int i = 0; i <= acsize; ++i)
        ans += f[m][i][S];
    printf("%lld\n", ans);
    if(ans > 42) return 0;
    for(int i = 0; i <= acsize; ++i)
        if(f[m][i][S]) dfs(m, i, S, c[i]);
    sort(str.begin(), str.end());
    while(!str.empty()){
        (str.back()).print(); str.pop_back();
    }
    return 0;
}
[JSOI2009]密码 [AC自动机]的更多相关文章
- BZOJ 1559: [JSOI2009]密码( AC自动机 + 状压dp )
		建AC自动机后, dp(x, y, s)表示当前长度为x, 在结点y, 包括的串的状态为s的方案数, 转移就在自动机上走就行了. 对于输出方案, 必定是由给出的串组成(因为<=42), 所以直接 ... 
- BZOJ1559[JSOI2009]密码——AC自动机+DP+搜索
		题目描述 输入 输出 样例输入 10 2 hello world 样例输出 2 helloworld worldhello 提示 这题算是一个套路题了,多个串求都包含它们的长为L的串的方案数. 显然是 ... 
- [BZOJ1559][JSOI2009]密码(AC自动机)
		http://www.lydsy.com/JudgeOnline/problem.php?id=1559 2009年的省选题虽然比起现在简单了不少,但对我来说还是很有挑战性的. 首先对于这种多串匹配问 ... 
- [BZOJ1559]密码 AC自动机+状压
		问题 K: [JSOI2009]密码 时间限制: 1 Sec 内存限制: 64 MB 题目描述 众所周知,密码在信息领域起到了不可估量的作用.对于普通的登陆口令,唯一的破解 方法就是暴力破解一逐个尝 ... 
- 【BZOJ4327】JSOI2012 玄武密码 AC自动机
		[BZOJ4327]JSOI2012 玄武密码 Description 在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河.相传一日,一缕紫气从天而至,只一瞬间便消失在了进香 ... 
- BZOJ4327 [JSOI2012] 玄武密码 [AC自动机]
		题目传送门 玄武密码 Description 在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河.相传一日,一缕紫气从天而至,只一瞬间便消失在了进香河中.老人们说,这是玄武神 ... 
- Vijos P1951 玄武密码 (AC自动机)
		描述 在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河.相传一日,一缕紫气从天而至,只一瞬间便消失在了进香河中.老人们说,这是玄武神灵将天书藏匿在此. 很多年后,人们终于在 ... 
- TZOJ 5986 玄武密码(AC自动机)
		描述 在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河.相传一日,一缕紫气从天而至,只一瞬间便消失在了进香河中.老人们说,这是玄武神灵将天书藏匿在此. 很多年后,人们终于在 ... 
- BZOJ 4327 [JSOI2012]玄武密码 (AC自动机)
		题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=4327 题解: 做法挺显然,建出AC自动机之后在上面跑,标记所有走过的点,然后再进行递推 ... 
随机推荐
- 第三章 CLR如何解析引用类型
			C#编译器将代码打包成托管模块后,接着会将这些模块合并成程序集,然后统一加载到一个具体的目录,CLR在这个目录查找并且加载所需要的DLL或者exe. 程序集分类:弱命名程序集和强命名程序集,强命名程序 ... 
- Linux高级运维  第二章  Linux基本操作和自己动手组装服务器
			2.1 Linux网络相关概念和修改IP地址的方法 2.1.1 网卡的命名规则 Centos 6的网卡命名方式:它会根据情况有所改变而非唯一且固定,在CENTOS6之前,网络接口使用连 ... 
- vue 模板template
			入门 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8& ... 
- vue中使用provide和inject刷新当前路由(页面)
			1.场景 在处理列表时,常常有删除一条数据或者新增数据之后需要重新刷新当前页面的需求. 2.遇到的问题 1. 用vue-router重新路由到当前页面,页面是不进行刷新的 2.采用window.rel ... 
- OPPO K3在哪里打开USB调试模式的完美方法
			当我们使用pc链接安卓手机的时候,如果手机没有开启USB调试模式,pc则无法成功识别我们的手机,这个时候我们需要找解决方法将手机的USB调试模式打开,今天我们介绍OPPO K3如何开启USB调试模式的 ... 
- 解决Angular2  (SystemJS) XHR error (404 Not Found) loading traceur
			初学Angular2,跟着Angular2中文网学到HTTP这一节时出现了一个异常: GET http://localhost:3000/traceur 404 (Not Found) Error: ... 
- 使用docker安装mysql和redis
			本文介绍在linux下使用docker安装mysql和redis. 原文地址:代码汇个人博客 http://www.codehui.net/info/59.html 测试环境:centos7.6,do ... 
- leetcode题解-122买卖股票的最佳时期
			题目 leetcode题解-122.买卖股票的最佳时机:https://www.yanbinghu.com/2019/03/14/30893.html 题目详情 给定一个数组,它的第 i 个元素是一支 ... 
- June. 25th 2018, Week 26th. Monday
			Change in all things is sweet. 有改变就会有美好. From Aristole. Change is always good, but embracing change ... 
- Pycharm 常用快捷键
			常用快捷键 快捷键 功能 Ctrl + Q 快速查看文档 Ctrl + F1 显示错误描述或警告信息 Ctrl + / 行注释(可选中多行) Ctrl + Alt + L 代码格式化 Ctrl + A ... 
