[FJOI2011] 前缀与后缀
来源:互联网 发布:数据员的岗位职责 编辑:程序博客网 时间:2024/05/05 02:25
题目描述
现有n个由小写字母组成的单词,然后给定m对小写的前缀与后缀。对于每对前缀与后缀,请你求出在n个单词中有多少个同时包含他们。
输入格式
输入第一行为n,接下去n行每行包含一个单词,合起来总字符数不超过100000个。
接下去一行为m,接下去m行每行包含一对空格隔开的前缀与后缀,合起来总字符数不超过200000个。
输出格式
对输出m行,每行一个整数为对应所求。
样例数据
样例输入
3
aaaaa
abacabaa
avtobus
6
a a
a aa
aa a
aaaaa aaaa
abac caba
abac a
样例输出
2
2
1
1
0
1
题目分析
将每个单词转化为:单词_单词
比如avtobus转为avtobus_avtobus
在前缀和后缀间添加下划线并反向插入AC自动机
比如abac a转为a_abac
接着依次匹配主串统计个数
注意可能有重复的字符串,需将统计写在树的内部
源代码
#include<algorithm>#include<iostream>#include<iomanip>#include<cstring>#include<cstdlib>#include<vector>#include<cstdio>#include<cmath>#include<queue>using namespace std;inline const int Get_Int() { int num=0,bj=1; char x=getchar(); while(x<'0'||x>'9') { if(x=='-')bj=-1; x=getchar(); } while(x>='0'&&x<='9') { num=num*10+x-'0'; x=getchar(); } return num*bj;}const int maxn=400005;struct Tree { int child[28],fail,tot,index,sum; //fail失败指针 void clear() { memset(child,0,sizeof(child)); fail=0; tot=0; index=0; sum=0; }};int root=1,Map[400005];struct Aho_Corasick_Automaton { //AC自动机 int cnt; Tree tree[maxn]; void init() { cnt=1; memset(tree,0,sizeof(tree)); } void insert(string s,int id) { int now=root,len=s.length(); for(int i=0; i<len; i++) { int j; if(s[i]=='_')j=27; else j=s[i]-'a'; if(!tree[now].child[j]) { tree[++cnt].clear(); tree[now].child[j]=cnt; } now=tree[now].child[j]; } tree[now].tot=1; Map[id]=now; } void buildfail() { //Bfs构造Fail指针 queue<int>Q; Q.push(root); while(!Q.empty()) { int Now=Q.front(); Q.pop(); for(int i=0; i<28; i++) { int Next=tree[Now].child[i]; if(Next==0)continue; //儿子不存在 Q.push(Next); int fatherfail=tree[Now].fail; //父亲的失败指针 while(fatherfail&&!tree[fatherfail].child[i])fatherfail=tree[fatherfail].fail; //寻找可退回点 if(fatherfail)tree[Next].fail=tree[fatherfail].child[i]; //如果存在满足条件的点则设置失败指针 else tree[Next].fail=root; //否则指回root } } } int match(string s) { //匹配字符串s int t=root,len=s.length(),ans=0; for(int i=0; i<len; i++) { int j; if(s[i]=='_')j=27; else j=s[i]-'a'; while(t&&!tree[t].child[j])t=tree[t].fail; //不匹配 if(t)t=tree[t].child[j]; //匹配 else t=root; //返回root for(int j=t; j; j=tree[j].fail) tree[j].sum+=tree[j].tot; } return ans; }};Aho_Corasick_Automaton ac;int n,m;string s[400005];int main() { ios::sync_with_stdio(false); cin>>n; for(int i=1; i<=n; i++) { cin>>s[i]; s[i]=s[i]+'_'+s[i]; } cin>>m; ac.init(); for(int i=1; i<=m; i++) { string a,b; cin>>a>>b; ac.insert(b+'_'+a,i); } ac.buildfail(); for(int i=1; i<=n; i++)ac.match(s[i]); for(int i=1; i<=m; i++)printf("%d\n",ac.tree[Map[i]].sum); return 0;}
0 0
- [FJOI2011] 前缀与后缀
- 前缀表达式与后缀表达式
- 中缀表达式与前缀,后缀的转换
- 前缀式与后缀式的差别
- 前缀方式与后缀方式的识别
- 好办法牢记前缀++(--)与后缀++(--)执行顺序
- ++与 -- 操作符前缀形式与后缀形式的区别
- [Java] i++与++i的区别(后缀++与前缀++)
- 哑元与运算符重载:前缀++与后缀++
- 操作符++/--的前缀形式与后缀形式的区别
- 操作符重载,区分前缀与后缀操作符
- 前缀积与后缀积求大数取模
- (转)前缀、中缀、后缀表达式及转换与应用
- HDU 2594 Simpsons’ HiddenTalents(KMP:后缀与前缀)
- JavaEE_Mybatis_SpringMVC_Spring_lesson4_配置视图解析器的前缀与后缀
- 深度解析前缀操作符与后缀操作符
- 二叉树与表达式(前缀,中缀,后缀表达式)
- 简述前缀运算符与后缀运算符
- 小程聊微服务-基于dubbo的mock测试系统
- ASN1 基础知识7
- Bubble sort(冒泡排序)
- PHP删除当前目录下统计代码块
- 对象不支持此属性或方法: 'Response.CharSet'
- [FJOI2011] 前缀与后缀
- dpdk简介
- JAVA中int、String的类型转换
- 二层交换机,三层交换机的区别
- 神经性皮炎
- Android从相册选择一个图片、剪切、上传
- JAVA发送HttpClient请求及接收请求结果过程
- 大型网站架构之分布式消息队列
- js window.open 传递中文参数出现乱码解决办法