[BZOJ 1559] [JSOI2009] 密码 【AC自动机DP】
题目链接:BZOJ - 1559
题目分析
将给定的串建成AC自动机,然后在AC自动机上状压DP。
转移边就是Father -> Son 或 Now -> Fail。
f[i][j][k] ,表示到了字符串第 i 位,在AC自动机的第 j 个节点上,状态为 k 的方案数。
状态 k 是一个二进制压缩的,表示已经包含了哪些给定串的整数。
然后...输出方案....这个太麻烦了...我是从最后状态DFS向前反推。
另外的问题是我写的AC自动机DP无法正确处理给定串存在串 A 包含串 B 的情况,所以我必须将被其他给定串包含的给定串忽略。
要去掉所有被其他某个给定串包含的给定串。需要在建完Fail之后从每个节点向Fail一直走到Root,将一路上的所有节点都设定为不是给定串。
当然要记录一下某个节点沿Fail到Root的路径已经被处理的话就 break。
我刚开始写的代码只能处理一个串是另一个串前缀或后缀的情况,被包含在中间的情况不能处理,但是仍然在BZOJ AC了。
代码
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue> using namespace std; const int MaxL = 15, MaxM = 15, MaxC = 27, MaxN = 25 + 5, MaxNode = 255 + 5; typedef long long LL; int n, m, l, Index, Tot, MT, Top; LL Ans;
LL f[MaxN][MaxNode][1024 + 15]; char S[MaxL]; struct Str
{
char str[MaxN];
} Sol[50], DS; bool Cmp(Str s1, Str s2)
{
for (int i = 0; i < n; ++i)
{
if (s1.str[i] == s2.str[i]) continue;
return s1.str[i] < s2.str[i];
}
return false;
} struct Trie
{
int Num, ID, c, isStr;
bool Ed;
Trie *Child[MaxC], *Fail;
} TA[MaxNode], *P = TA, *Root, *Zero; void Insert(char *S, int l)
{
Trie *Now = Root;
int t;
for (int i = 1; i <= l; ++i)
{
t = S[i] - 'a';
if (Now -> Child[t] == NULL)
{
++P; P -> Num = 0; P -> ID = ++Tot; P -> c = t;
Now -> Child[t] = P;
}
Now = Now -> Child[t];
}
Now -> isStr = 1;
} void Init_AC()
{
Index = 0; Tot = 0;
Zero = P; //ID : 0
Root = ++P; Root -> ID = ++Tot; //ID : 1
for (int i = 0; i < 26; ++i) Zero -> Child[i] = Root;
Zero -> Fail = NULL;
for (int i = 0; i < 26; ++i) Root -> Child[i] = NULL;
Root -> Fail = Zero;
} queue<Trie *> Q; void Build_Fail()
{
while (!Q.empty()) Q.pop();
Q.push(Root);
Trie *Now, *Temp;
while (!Q.empty())
{
Now = Q.front(); Q.pop();
for (int i = 0; i < 26; ++i)
{
if (Now -> Child[i] == NULL) Now -> Child[i] = Now -> Fail -> Child[i];
else
{
Now -> Child[i] -> Fail = Now -> Fail -> Child[i];
Q.push(Now -> Child[i]);
}
}
}
for (Trie *j = TA; ; ++j)
{
Temp = j -> Fail;
while (Temp != NULL && Temp != Root && Temp != Zero)
{
if (Temp -> Ed) break;
Temp -> Ed = true;
Temp -> isStr = -1;
Temp = Temp -> Fail;
}
if (j == P) break;
}
for (Trie *j = TA; ; ++j)
{
if (j -> isStr == 1) j -> Num = ++Index;
else j -> Num = 0;
if (j == P) break;
}
} void DP()
{
f[0][1][0] = 1;
MT = (1 << Index) - 1;
for (int i = 0; i <= n; ++i)
for (int j = 0; j <= Tot; ++j)
for (int k = 0; k <= MT; ++k)
if (f[i][j][k])
{
for (int t = 0; t < 26; ++t)
{
if (TA[j].Child[t] -> Num == 0) f[i + 1][TA[j].Child[t] -> ID][k] += f[i][j][k];
else f[i + 1][TA[j].Child[t] -> ID][k | (1 << (TA[j].Child[t] -> Num - 1))] += f[i][j][k];
}
}
Ans = 0;
for (int i = 1; i <= Tot; ++i) Ans += f[n][i][MT];
} void DFS(int l, int x, int y, int t)
{
//printf("Begin %d %d %d %c\n", l, x, y, t + 'a');
DS.str[l - 1] = 'a' + t;
if (l == 1)
{
Sol[++Top] = DS;
return;
}
for (int i = 1; i <= Tot; ++i)
if (f[l - 1][i][y] && TA[i].Child[t] -> ID == x)
{
if (i == 1) for (int j = 0; j < 26; ++j) DFS(l - 1, i, y, j);
else DFS(l - 1, i, y, TA[i].c);
}
int yy;
if (TA[x].Num != 0)
{
yy = y - (1 << (TA[x].Num - 1));
for (int i = 1; i <= Tot; ++i)
if (f[l - 1][i][yy] && TA[i].Child[t] -> ID == x)
{
if (i == 1) for (int j = 0; j < 26; ++j) DFS(l - 1, i, yy, j);
else DFS(l - 1, i, yy, TA[i].c);
}
}
//printf("End %d %d %d %c\n", l, x, y, t + 'a');
} void Get_Sol()
{
Top = 0;
for (int i = 1; i <= Tot; ++i)
if (f[n][i][MT])
{
if (i == 1)
{
for (int j = 0; j < 26; ++j)
DFS(n, i, MT, j);
}
else DFS(n, i, MT, TA[i].c);
}
} int main()
{
scanf("%d%d", &n, &m);
Init_AC();
Index = 0;
for (int i = 1; i <= m; ++i)
{
scanf("%s", S + 1);
l = strlen(S + 1);
Insert(S, l);
}
Build_Fail();
DP();
printf("%lld\n", Ans);
if (Ans <= 42)
{
Get_Sol();
sort(Sol + 1, Sol + Ans + 1, Cmp);
for (int i = 1; i <= Ans; ++i)
{
Sol[i].str[n] = 0;
printf("%s\n", Sol[i].str);
}
}
return 0;
}
[BZOJ 1559] [JSOI2009] 密码 【AC自动机DP】的更多相关文章
- BZOJ 1559: [JSOI2009]密码( AC自动机 + 状压dp )
建AC自动机后, dp(x, y, s)表示当前长度为x, 在结点y, 包括的串的状态为s的方案数, 转移就在自动机上走就行了. 对于输出方案, 必定是由给出的串组成(因为<=42), 所以直接 ...
- BZOJ 1559 JSOI2009 密码 状压dp+AC自动机+搜索
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1559 分析: 这个题意真的是很**啊!!!直接说每一个字符串至少出现一次不就好了吗... ...
- BZOJ1559[JSOI2009]密码——AC自动机+DP+搜索
题目描述 输入 输出 样例输入 10 2 hello world 样例输出 2 helloworld worldhello 提示 这题算是一个套路题了,多个串求都包含它们的长为L的串的方案数. 显然是 ...
- [JSOI2009]密码 [AC自动机]
题面 bzoj luogu 首先看到这题就知道随便暴枚 只要是多项式算法都能过 先常规建AC自动机 注意被别的单词包含的单词没有存在的价值 剩余单词状压 大力dp f[长度][节点编号][状态] \( ...
- [BZOJ1559][JSOI2009]密码(AC自动机)
http://www.lydsy.com/JudgeOnline/problem.php?id=1559 2009年的省选题虽然比起现在简单了不少,但对我来说还是很有挑战性的. 首先对于这种多串匹配问 ...
- [bzoj] 1030 文本生成器 || AC自动机+dp
原题 给出n个字符串,求随机生成一个m长度的字符串,有多少个是可辨识的(即出现了n个字符串中的任意字符串) 正难则反 求有多少个不可辨识的,26^m-不可辨识即为答案 f[i][j]表示填到第i个字符 ...
- [BZOJ 3530] [Sdoi2014] 数数 【AC自动机+DP】
题目链接:BZOJ - 3530 题目分析 明显是 AC自动机+DP,外加数位统计. WZY 神犇出的良心省选题,然而去年我太弱..比现在还要弱得多.. 其实现在做这道题,我自己也没想出完整解法.. ...
- bzoj 1030 [JSOI2007]文本生成器(AC自动机+DP)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1030 [题意] 给n个小串,随机构造一个长为m的大串,一个串合法当且仅当包含一个或多个 ...
- 【BZOJ】4861: [Beijing2017]魔法咒语 AC自动机+DP+矩阵快速幂
[题意]给定n个原串和m个禁忌串,要求用原串集合能拼出的不含禁忌串且长度为L的串的数量.(60%)n,m<=50,L<=100.(40%)原串长度为1或2,L<=10^18. [算法 ...
随机推荐
- C#调用java接口报“Fault occurred while processing”异常问题
服务在通常项目中总是要用到的C#的webservice.wcf,还有第三方的,比如java服务.一般来说调用都不会有什么问题,因为服务的标准都是一样的.要注意的就是:1.参数个数匹配:2.参数类型和返 ...
- android86 监听SD卡状态,勒索软件,监听应用的安装、卸载、更新,无序广播有序广播
* 添加权限 <uses-permission android:name="android.permission.RECEIVE_SMS"/> * 4.0以后广播接收者 ...
- mybatis09
1mybatis开发dao的方法 .1SqlSession作用范围 是使用局部变量.成员变量,还是形参? 1.1.1SqlSessionFactoryBuilder SqlSessionFactory ...
- hadoop错误org.apache.hadoop.yarn.exceptions.YarnException Unauthorized request to start container
错误: 14/04/29 02:45:07 INFO mapreduce.Job: Job job_1398704073313_0021 failed with state FAILED due to ...
- NDK开发之获得域和方法描述符
在NDK开发之调用方法和NDK开发之访问域两篇博客中,我们在获得域ID和方法ID时都需要一个叫做描述符的参数,那么在实际开发中我们怎么知道我们要调用的域或者方法的描述符呢? 一个简单的方法就是使用Ja ...
- 關於Validform 控件 值得注意的地方
Validform控件其實用起來挺方便的,直接百度就能找到官網,有直接的demo做參考.這些我就不提了,我所要說的是關於Validform控件的ajax的提交. Validform中有個參數ajaxP ...
- Android 设计随便说说之简单实践(合理组合)
上一篇(Android 设计随便说说之简单实践(模块划分))例举了应用商店设计来说明怎么做模块划分.模块划分主要依赖于第一是业务需求,具体是怎么样的业务.应用商店则包括两个业务,就是向用户展示appl ...
- javascript-图片横向无缝隙滚动(可在服务器运行)
前两次弄'图片横向滚动'javascript,在本地上运行得很美,可是一上到我们学校后台的服务器,就有很多问题,这个算是行的了. css代码: <style type="text/cs ...
- 如何在ASP.NET 项目中使用Silverlight页面
闲来无事,想写个网站玩玩,比较懒,不想写太多的样式来美化,看中了Silverlight,样式布局比较省事,但是又不想全部都用Silverlight 来写,所以才有此一文. 其实Silverlight最 ...
- andriod 中设置sdk升级代理服务器
Android SDK 在线更新镜像服务器资源: 大连东软信息学院镜像服务器地址: http://mirrors.neusoft.edu.cn 端口:80 北京化工大学镜像服务器地址: IPv4: h ...