题目大意:给定n个目标串和m个模式串,问这m个模式串每个在多少个目标串中出现过,以及n个目标串每个以最多多少个模式串为子串
我错了……就算用fail树+set启发式合并也优化不到O(nlog^2n)……这题的数据范围相当无解啊
首先将所有名字和点名的字符串全都插进AC自动机
将每个点上开一个set记录这个点是哪些喵星人的名字的前缀
然后建立fail树 沿着fail树从下到上启发式合并
每合并完一个点 如果这个点是某次点名的字符串 那么这次点名点到的喵星人就是这个点的set中的所有元素 统计答案即可
统计答案以外的操作显然是O(nlog^2n) 但是统计答案这里还是没有避免高复杂度
最终复杂度为O(nlog^2n+Σans2) 其中ans2是第二问的答案
感觉这个算法的瓶颈就在Σans2上了……或许我们可以换一种做法统计ans2?感觉……不是很必要的样子……
#include <set>
#include <map>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 200200
using namespace std;
struct Trie{
Trie *fail;
map<int,Trie*> son;
set<int> s;
vector<Trie*> fail_son;
int ed,cnt;
}*root,mempool[M],*C=mempool;
int n,m,ans1[50500],ans2[20200];
int substitute[50500];
void Insert(Trie* &p,int left,int pos,bool flag)
{
if(!p) p=C++;
if(!flag) p->s.insert(pos);
if(!left)
{
if(flag)
{
if(p->ed)
substitute[p->ed]=pos;
p->ed=pos;
p->cnt++;
}
return ;
}
int temp;
scanf("%d",&temp);
Insert(p->son[temp],left-1,pos,flag);
}
void Build_Tree()
{
static Trie *q[M];
static int r,h;
map<int,Trie*>::iterator it;
for(it=root->son.begin();it!=root->son.end();it++)
{
it->second->fail=root;
root->fail_son.push_back(it->second);
q[++r]=it->second;
}
while(r!=h)
{
Trie *p=q[++h];
for(it=p->son.begin();it!=p->son.end();it++)
{
Trie *temp=p->fail;
while(temp!=root&&!temp->son[it->first])
temp=temp->fail;
if(temp->son[it->first])
temp=temp->son[it->first];
it->second->fail=temp;
temp->fail_son.push_back(it->second);
q[++r]=it->second;
}
}
}
void DFS(Trie *p)
{
vector<Trie*>::iterator it;
set<int>::iterator _it;
for(it=p->fail_son.begin();it!=p->fail_son.end();it++)
{
DFS(*it);
set<int>&s=p->s;
set<int>&son_s=(*it)->s;
if( s.size()<son_s.size() )
swap(s,son_s);
for(_it=son_s.begin();_it!=son_s.end();_it++)
s.insert(*_it);
son_s.clear();
}
if(p->ed)
{
ans1[p->ed]=p->s.size();
for(_it=p->s.begin();_it!=p->s.end();_it++)
ans2[*_it]+=p->cnt;
}
}
int main()
{
int i,x;
cin>>n>>m;
for(i=1;i<=n;i++)
{
scanf("%d",&x);
Insert(root,x,i,0);
scanf("%d",&x);
Insert(root,x,i,0);
}
for(i=1;i<=m;i++)
{
scanf("%d",&x);
Insert(root,x,i,1);
}
Build_Tree();
DFS(root);
for(i=m;i;i--)
if(substitute[i])
ans1[i]=ans1[substitute[i]];
for(i=1;i<=m;i++)
printf("%d\n",ans1[i]);
for(i=1;i<=n;i++)
printf("%d%c",ans2[i],i==n?'\n':' ');
return 0;
}