HDU 6096 AC自动机
Posted 天翎月
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 6096 AC自动机相关的知识,希望对你有一定的参考价值。
n个字符串 m个询问 每个询问给出前后缀 并且不重合 问有多少个满足
m挺大 如果在线只能考虑logn的算法
官方题解:对n个串分别存正序倒序 分别按照字典序sort 每一个串就可以被化作一个点 那么对于每一个询问 前后缀都会有一个范围 那就是求这个范围里面的点的个数
官方题解转化到了求矩形并 然而没理解怎么转化 倒是想出来了kdtree直接求范围点 由于前后缀不能重合 即如果有aa aa这个询问 我的办法会找到aaa 就要进行去重
我用map记录 然后每次询问都查询一下。。跑的特别慢。。
但是在写这个博客的时候想出来 可以存三维点 第三维代表这n个串的长度 那么就可以查询len>某个值 进行三维查询
不知道复杂度是不是还会很高。。明天试一下
我的做法:对于n个串 abcde -> abcde*abcde m个询问 ab de -> de*ab 这样直接离线n个串 先把m个询问插进去 记录一下id 直接用n个串跑 最后输出ans
在其中记录fail树上每个点的dep 如果这个点的dep > n个串的长度 就不对答案贡献
但是这样又有了一个新的问题 一模一样的询问会少算 于是我用map<string,int>来记录一下是否已经出现 如果出现了那么这个询问不insert 而是直接指向最早出现的询问
写了一万个bug...不过顺便学习了线段树求矩形面积/周长并
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<vector> #include<map> #include<queue> #include<algorithm> using namespace std; #define L long long #define pb push_back string a[100050] ; int n , m ; char s[500050 * 2] , s2[500050*2]; int ans[100050] ; struct tire{ int nex[700010*2][27] , fail[700010*2], id[700010*2]; int last[700010*2] ; int dep[700010*2] ; int root,l; int newnode(){ for(int i=0;i<27;i++)nex[l][i]=-1; last[l]=0; id[l++]=0; return l-1; } void init(){ l=0; root=newnode(); dep[root]=0; } void inse(string s ,int idd){ int le = s.length() ; int now=root; for(int i=0;i<le;i++){ int x; if(s[i]>=‘a‘&&s[i]<=‘z‘)x=s[i]-‘a‘; else x=26; if(nex[now][x] == -1) { nex[now][x] = newnode(); } now=nex[now][x]; dep[now]=i+1; } id[now]=idd; } void build() { queue<int>q; fail[root]=root; for(int i=0;i<27;i++){ if(nex[root][i]==-1) nex[root][i]=root; else { fail[nex[root][i]]=root; q.push(nex[root][i]); } } while(!q.empty()){ int now=q.front();q.pop(); for(int i= 0;i<27;i++){ if(nex[now][i]==-1) nex[now][i]=nex[fail[now]][i] ; else { fail[nex[now][i]] = nex[fail[now]][i] ; q.push(nex[now][i]) ; } } } } void query(string s, int cd , int num){ int le = s.length() ; int now=root; int res = 0 ; for(int i = 0 ; i < le ; i ++ ) { int x; if(s[i]>=‘a‘&&s[i]<=‘z‘)x=s[i]-‘a‘; else x=26; now = nex[now][x]; int temp=now; while(temp!=root){ if(id[temp]!=0 && dep[temp] <= cd+1){ ans[id[temp]]++; } temp = fail[temp] ; } } } }ac; map<string,int>mp; int main () { int t ; scanf("%d",&t); while(t -- ) { mp.clear(); ac.init() ; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ cin>>a[i]; } string c; memset(ans,0,sizeof(ans)); for(int i=1;i<=m;i++){ string s1,s2; cin>>s1>>s2; s2+="*";s2+=s1; if(mp[s2]!=0) ans[i]=mp[s2]*-1; else{ ac.inse(s2,i); mp[s2]=i; } } ac.build(); for(int i=1;i<=n;i++){ int len=a[i].length() ; string s=a[i];s+="*";s+=a[i]; ac.query(s , len , i) ; } for(int i=1;i<=m;i++){ if(ans[i]<0){ printf("%d\n",ans[ans[i]*(-1)]); } else { printf("%d\n",ans[i]); } } } }
以上是关于HDU 6096 AC自动机的主要内容,如果未能解决你的问题,请参考以下文章
HDU - 6096 :String (AC自动机,已知前后缀,匹配单词,弱数据)