BZOJ 4502: 串 AC自动机
4502: 串
Time Limit: 30 Sec Memory Limit: 512 MB
Submit: 195 Solved: 95
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
ab
ac
Sample Output
HINT
1<=n<=10000,每个字符串非空且长度不超过30,均为小写字母组成。
Source
颂魔和毒爷把这道题加强了一下$\sum S \le 10^6$,然后给了一个更容易的做法。我偷一发题解.....
正解大概是讲:先钦定一个串C,只在最右边分割点统计。对于{S}中两前缀A,B。定义(A,B)合法仅当不存在划分B的一个前缀,接到A后面得到的(A',B')。那么就考虑一对(A,B)是否合法。
先枚举B,然后再统计多少A后面可以接B的前缀。这里是可以接,而不是接多少次,所以直接用最短的前缀其判断。
这个最短的另一个要求是B'也存在{S}集中。所以可以等价于求一个最长的B'。就是找一个最长的B的后缀,这个可以用fail树求出。
由B'就定位B的最短前缀(Trie树定位),然后就统计它是{S}多少个A‘的后缀(用fail树统计)。
无声PPT
Code
#include< cstdio >
#include< cstring > #define gec getchar
#define FILE(F) freopen(F".in","r",stdin),freopen(F".out","w",stdout)
#define DEBUG fprintf(stderr,"Passing [%s] in Line (%d)\n",__FUNCTION__,__LINE__) typedef long long ll;
template
inline void read(T &x)
{
x=0;bool f=0;char c=gec();
for(;c<'0'||c>'9';c=gec())f=(c=='-');
for(;c>='0'&&c<='9';c=gec())x=x*10+c-'0';
x=f?-x:x;
} const int MAXN(1000010);
int Case,n,leng; char str[MAXN];
ll Ans; namespace ACmaton
{
struct ACtrie
{
int nx[26],fail,sum,Dep;
}trie[MAXN];int ktot=1,root=1; void ins()
{
int k=1;
for(int i=1;i<=leng;i++)
{
if(!trie[k].nx[str[i]-'a'])trie[k].nx[str[i]-'a']=++ktot;
trie[trie[k].nx[str[i]-'a']].Dep=trie[k].Dep+1;
k=trie[k].nx[str[i]-'a'];
}
} int que[MAXN],l,h,now;
void BFS()
{
for(int v=0;v<26;v++)
if(trie[root].nx[v])
{
trie[trie[root].nx[v]].fail=root;
que[++l]=trie[root].nx[v];
}else trie[root].nx[v]=root;
while(h<l)
{
now=que[++h];
for(int v=0;v<26;v++)
if(trie[now].nx[v])
{
trie[trie[now].nx[v]].fail=trie[trie[now].fail].nx[v];
que[++l]=trie[now].nx[v];
}else trie[now].nx[v]=trie[trie[now].fail].nx[v];
}
} int p[MAXN],cnt[MAXN];
void Pretreat()
{
for(int i=1;i<=ktot;i++)cnt[trie[i].Dep]++;
for(int i=1;i<=ktot;i++)cnt[i]+=cnt[i-1];
for(int i=ktot;i>=1;i--)p[cnt[trie[i].Dep]--]=i;
for(int i=ktot;i>=1;i--)
{
trie[p[i]].sum++;
trie[trie[p[i]].fail].sum+=trie[p[i]].sum;
}
trie[root].sum=1;
} int st[MAXN],tp;
void Dfs(int x)
{
st[++tp]=x;
for(int v=0;v<26;v++)
if(trie[trie[x].nx[v]].Dep==trie[x].Dep+1)Dfs(trie[x].nx[v]);
int Pre=trie[x].Dep-trie[trie[x].fail].Dep;
tp--;if(trie[x].fail!=root)Ans-=trie[st[Pre+1]].sum-1;//保留本身一个
} }using namespace ACmaton; int main()
{
FILE("string");
read(Case);
read(n);
for(int i=1;i<=n;i++)
{
scanf("%s",str+1);leng=strlen(str+1);
ins();
}
Ans=((ll)ktot-1ll)*(ktot-1);
BFS();
Pretreat();
Dfs(root);
printf("%lld\n",Ans);
return 0;
}
BZOJ 4502: 串 AC自动机的更多相关文章
- BZOJ1195[HNOI2006]最短母串——AC自动机+BFS+状态压缩
题目描述 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. 输入 第一行是一个正整数n(n<=12),表示给定的字符串的 ...
- BZOJ1195 [HNOI2006]最短母串 AC自动机 bfs
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 传送门 - BZOJ1195 题意概括 给出一堆串,然后求一个包含这些串的所有串的最短的中的字典序最小的. 题解 先造一个AC ...
- 【bzoj1195】[HNOI2006]最短母串 AC自动机+状态压缩+BFS最短路
原文地址:http://www.cnblogs.com/GXZlegend/p/6825226.html 题目描述 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串 ...
- Bzoj1195 [HNOI2006]最短母串 [AC自动机]
Time Limit: 10 Sec Memory Limit: 32 MBSubmit: 1304 Solved: 439 Description 给定n个字符串(S1,S2,„,Sn),要求找 ...
- [HNOI2006]最短母串 (AC自动机+状压)
Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. Input 第一行是一个正整数n(n<=12) ...
- BZOJ [Poi2000]病毒 AC自动机_DFS_细节
Code: #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) # ...
- bzoj1195 [HNOI2006]最短母串 AC 自动机+状压+bfs
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=1195 题解 建立 AC 自动机,然后构建出 trie 图. 然后直接在 trie 图上走.但是 ...
- bzoj 3172 单词 ac自动机|后缀数组
题目大意: 给定n个字符串连成了一篇文章,问每个字符串在这篇文章中出现的次数,可重复覆盖 这里ac自动机和后缀数组都可以做 当然后缀数组很容易就解决,但是相对时间消耗高 这里就只讲ac自动机了 将每个 ...
- BZOJ 1195: [HNOI2006]最短母串 AC自动机+状压+搜索
思路比较直接. 由于 $n$ 很小,直接定义 $f[i][j]$ 表示当前在自动机中的节点 $i,$ 被覆盖串的集合为 $j$ 的方案数. #include <bits/stdc++.h> ...
随机推荐
- HDU-Digital Roots(思维+大数字符串模拟)
The digital root of a positive integer is found by summing the digits of the integer. If the resulti ...
- 2015苏州大学ACM-ICPC集训队选拔赛(2) 1001 1003 1010
草爷要的榜 Problem Description 苏州大学代表队又勤奋地开始了训练.今天开了一场时长5小时的组队训练赛,苏州大学的n(1<=n<=100)支校队奋力拼(hua)搏(shu ...
- LDAP环境搭建 OpenLDAP和phpLDAPadmin -- yum版
前言: 前两天公司要求做一个使用LDAP和Kerberos做一个认证授权系统,然后开始学习LDAP相关知识,期间找了不少博客按照步骤来安装,可是很多博客在配置的时候,都会遇到安装过程中一两个问题卡 ...
- Ubuntu 14.04下MySQL服务器和客户端的安装
下面进行简单的配置 安装完成后通过修改/etc/mysql/my.cnf(此文件为mysql的配置文件).将文件中的binding-address=127.0.0.1注释掉.其它配置根据需要更改. H ...
- Linux链接器脚本详解
/* GNU linker script for STM32F405 */ /* Specify the memory areas */ MEMORY { FLASH (rx) : ORIGIN = ...
- 签名:实现参数字典排序,然后拼接为url参数形式
在很多地方请求参数需要做处理例如: 步骤 1.参数字典排序. 2.拼接字符. /// <summary> /// 生成签名 /// </summary> /// <par ...
- Linux中的netstat命令详解
功能说明 netstat是基于Netstat这个命令行工具的指令,它可以用来查询系统上的网络套接字连接情况,包括tcp,udp以及Unix套接字:另外它还能列出路由表,接口状态和多播成员等信息. 主要 ...
- Java类名 方法名 常量 变量的命名习惯
1.包 用于将完成不同功能的类分门别类,放在不同的目录(包)下,包的命名规则:将公司域名反转作为包名,对于包名,每个字母都需要小写. 如果定义类的时候没有使用package(包),那么java就认为我 ...
- c++ for_each( )学习
for_each()事实上是個 function template,其实质如下 [effective STL item 41] template<typename InputIterator, ...
- Kure讲HTML_HTML界面结构
1.HTML界面结构: 通常通过html开发的网页,它有一个自己固定的书写格式(类似于写信的时候也有固定的格式) <!-- DOCTYPE用来告诉浏览器用当前html文档是用html的哪个版本编 ...