BZOJ1559 [JSOI2009]密码 【AC自动机 + 状压dp】
题目链接
题解
考虑到这是一个包含子串的问题,而且子串非常少,我们考虑\(AC\)自动机上的状压\(dp\)
设\(f[i][j][s]\)表示长度为\(i\)的串,匹配到了\(AC\)自动机\(j\)号节点,且已匹配集合为\(s\)的方案数
直接在\(AC\)自动机上转移即可
但是为了防止使用\(last\)指针之类的,计算匹配的串,我们先将原串的集合去重和去包含关系
方案怎么办?
考虑到\(ans \le 42\),一定是刚好若干个原串以最长前后缀相同的方式相接
因为如果不是以最长前后缀的方式相接,那么一定存在更小的方案,这个时候就会多出若干空位置可以随便填
一个位置可以填\(26\)种字母,而且可以放在前缀或者后缀,所以有一个空位置就有\(52\)种方案,大于\(42\)种
所以可以放心\(O(n!)\)枚举排列相接
\(1A\)了很开心
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<cmath>
#include<queue>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
using namespace std;
const int maxn = 105,maxm = 100005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
int ch[maxn][26],fail[maxn],tag[maxn],cnt,len[12];
char s[12][12];
int isin[maxn];
int same[12][12];
LL f[26][105][1 << 10];
void ins(int p){
int u = 0,id;
for (int i = 1; i <= len[p]; i++){
id = s[p][i] - 'a';
u = ch[u][id] ? ch[u][id] : (ch[u][id] = ++cnt);
}
tag[u] |= (1 << p - 1);
}
void getf(){
queue<int> q;
for (int i = 0; i < 26; i++) if (ch[0][i]) q.push(ch[0][i]);
int u,v;
while (!q.empty()){
u = q.front(); q.pop();
for (int i = 0; i < 26; i++){
v = ch[u][i];
if (!v){
ch[u][i] = ch[fail[u]][i];
continue;
}
fail[v] = ch[fail[u]][i];
q.push(v);
}
}
}
int L,n;
int check(int u,int v){
if (len[u] > len[v]) return 0;
if (len[u] == len[v]){
for (int i = 1; i <= len[u]; i++)
if (s[u][i] != s[v][i])
return 0;
return 1;
}
for (int i = 1; i <= len[v] - len[u] + 1; i++){
int flag = true;
for (int j = 1; j <= len[u]; j++){
if (s[u][j] != s[v][i + j - 1]){
flag = false;
break;
}
}
if (flag) return 2;
}
return 0;
}
int cal(int u,int v){
for (int i = max(1,len[u] - len[v] + 1); i <= len[u]; i++){
int flag = true;
for (int j = 1; i + j - 1 <= len[u]; j++)
if (s[u][i + j - 1] != s[v][j]){
flag = false;
break;
}
if (flag) return len[u] - i + 1;
}
return 0;
}
int vis[maxn],a[maxn],ansi,Ltot;
struct node{
char s[30];
int len;
}ans[50];
inline bool operator <(const node& a,const node& b){
return strcmp(a.s + 1,b.s + 1) < 0;
}
void Check(){
int sum = Ltot;
for (int i = 1; i < n; i++)
sum -= same[a[i]][a[i + 1]];
if (sum == L){
ansi++;
for (int i = 1; i <= n; i++){
int u = a[i];
for (int j = same[a[i - 1]][u] + 1; j <= len[u]; j++){
ans[ansi].s[++ans[ansi].len] = s[u][j];
}
}
}
}
void dfs(int u){
if (u > n){
Check();
return;
}
for (int i = 1; i <= n; i++)
if (!vis[i]){
vis[i] = true;
a[u] = i;
dfs(u + 1);
vis[i] = false;
}
}
void work(){
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (i != j) same[i][j] = cal(i,j);
for (int i = 1; i <= n; i++) Ltot += len[i];
dfs(1);
sort(ans + 1,ans + 1 + ansi);
for (int i = 1; i <= ansi; i++)
printf("%s\n",ans[i].s + 1);
}
int main(){
L = read(); n = read();
for (int i = 1; i <= n; i++){
scanf("%s",s[i] + 1);
len[i] = strlen(s[i] + 1);
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (i != j ){
int t = check(i,j);
if (t == 2 || (t == 1 && i > j))
isin[i] = true;
}
int tot = 0;
for (int i = 1; i <= n; i++)
if (!isin[i]){
strcpy(s[++tot] + 1,s[i] + 1);
len[tot] = len[i];
ins(tot);
}
n = tot;
getf();
int maxv = (1 << n) - 1,u;
f[0][0][0] = 1;
for (int i = 0; i < L; i++){
for (int j = 0; j <= cnt; j++){
for (int s = 0; s <= maxv; s++){
if (!f[i][j][s]) continue;
for (int k = 0; k < 26; k++){
u = ch[j][k];
f[i + 1][u][s | tag[u]] += f[i][j][s];
}
}
}
}
LL ans = 0;
for (int i = 0; i <= cnt; i++)
ans += f[L][i][maxv];
printf("%lld\n",ans);
if (ans <= 42) work();
return 0;
}
BZOJ1559 [JSOI2009]密码 【AC自动机 + 状压dp】的更多相关文章
- BZOJ 1559: [JSOI2009]密码( AC自动机 + 状压dp )
建AC自动机后, dp(x, y, s)表示当前长度为x, 在结点y, 包括的串的状态为s的方案数, 转移就在自动机上走就行了. 对于输出方案, 必定是由给出的串组成(因为<=42), 所以直接 ...
- hdu 2825 aC自动机+状压dp
Wireless Password Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others ...
- HDU 3247 Resource Archiver(AC自动机 + 状压DP + bfs预处理)题解
题意:目标串n( <= 10)个,病毒串m( < 1000)个,问包含所有目标串无病毒串的最小长度 思路:貌似是个简单的状压DP + AC自动机,但是发现dp[1 << n][ ...
- zoj3545Rescue the Rabbit (AC自动机+状压dp+滚动数组)
Time Limit: 10 Seconds Memory Limit: 65536 KB Dr. X is a biologist, who likes rabbits very much ...
- hdu2825 Wireless Password(AC自动机+状压dp)
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission ...
- hdu 4057--Rescue the Rabbit(AC自动机+状压DP)
题目链接 Problem Description Dr. X is a biologist, who likes rabbits very much and can do everything for ...
- [BZOJ1559]密码 AC自动机+状压
问题 K: [JSOI2009]密码 时间限制: 1 Sec 内存限制: 64 MB 题目描述 众所周知,密码在信息领域起到了不可估量的作用.对于普通的登陆口令,唯一的破解 方法就是暴力破解一逐个尝 ...
- BZOJ1559[JSOI2009]密码——AC自动机+DP+搜索
题目描述 输入 输出 样例输入 10 2 hello world 样例输出 2 helloworld worldhello 提示 这题算是一个套路题了,多个串求都包含它们的长为L的串的方案数. 显然是 ...
- hdu 6086 -- Rikka with String(AC自动机 + 状压DP)
题目链接 Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, s ...
随机推荐
- python七类之字典详解
一.字典 一.关键字:dict 1.字典是唯一的键值对数据,其表现形式: dic = {键:值},字典里的键必须保证是唯一的 2.键必须是不可变的数据类型: a.故列表是不能当键的 b.所 ...
- crest value &minimum
public class paixu { public static void main(String[] args) { double temp; double num[]={5.1, 7.12, ...
- (数据科学学习手札05)Python与R数据读入存出方式的总结与比较
在数据分析的过程中,外部数据的导入和数据的导出是非常关键的部分,而Python和R在这方面大同小异,且针对不同的包或模块,对应着不同的函数来完成这部分功能: Python 1.TXT文件 导入: 以某 ...
- Ubuntu14.04安装opencv2.4.13
本文参考相关链接:http://blog.csdn.net/honyniu/article/details/46390097 系 统:Ubuntu 14.04 x64 opencv版本:2.4.1 ...
- 如何在Moodle中显示PPT课件
Moodle中目前是不直接支持PPT的,所以需要曲线救国: 1.安装 iSpring Free 8版本,免费版,其实是一个PPT的插件,在PPT的工具栏中有显示. 2.打开PPT后,直接在该工具中进行 ...
- P1991 无线通讯网
P1991 无线通讯网 题目描述 国防部计划用无线网络连接若干个边防哨所.2 种不同的通讯技术用来搭建无线网络: 每个边防哨所都要配备无线电收发器:有一些哨所还可以增配卫星电话. 任意两个配备了一条卫 ...
- android去掉button默认的点击阴影
查了资料,发现别人都是说加一个style属性. style="?android:attr/borderlessButtonStyle" 加上了确实管用,但是我绝不是不求甚解的人.追 ...
- Flexbox布局模式的理解
个人博客地址: 雨中的鱼-前端知识分享 http://www.showhtml5.cc 分享干货,有兴趣的人可以一起来分享前端知识 加Q群:440279380 Flexbox,一种C ...
- 虚拟现实-VR-UE4-编译源代码后,无法运行
情况是这个样,在一开始我编译后,是可以运行,但是当我重新做系统后,再次运行时,每次都是到加载的18%的时候提示了如下错误 具体解决方法还没有找到,正在努力找中.........,会后续更新 同时希望有 ...
- 大批量复制Oracle数据表,连带复制主键约束,字段说明以及字段默认值(量产)
DECLARE CURSOR tab_name_cur IS SELECT table_name FROM user_tables ...