版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/86254592
题目:luogu4595.
题目大意:给定一个字符串和另外一个字符串集合,求它有多少个字符不能被任何一个字符串集合中的字符串匹配.
看起来很裸的题,可以直接对字符串集合建立AC自动机,然后每个节点记录一个最深的可以通过fail指针跳到的打了字符串结尾的节点,就可以在匹配的时候保证时间复杂度.
但是我们发现AC自动机的内存太大,在只有64M的内存下根本无法通过.于是我们考虑每次读入了较多个字符串时匹配一次,然后把AC自动机清空继续读入,这样可以保证空间复杂度,但会牺牲一定的时间(然而这道题并不卡时).
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
#define m(a) memset(a,0,sizeof(a))
const int C=26,N=500000,M=60;
struct Trie{
int s[C],fail,cnt,get,deep;
Trie(){m(s);fail=cnt=get=deep=0;}
}tr[N+9];
int cn,ans;
void Build(){tr[cn=0]=Trie();}
void Insert(char *c,int len){
int x=0;
for (int i=1;i<=len;++i)
if (tr[x].s[c[i]-'a']) x=tr[x].s[c[i]-'a'];
else {
tr[x].s[c[i]-'a']=++cn;
tr[cn]=Trie();
tr[cn].deep=tr[x].deep+1;
x=cn;
}
++tr[x].cnt;
}
queue<int>q;
void Get_fail(){
for (int i=0;i<C;++i)
if (tr[0].s[i]) q.push(tr[0].s[i]);
while (!q.empty()){
int x=q.front();q.pop();
tr[x].get=tr[x].cnt?x:tr[tr[x].fail].get;
for (int i=0;i<C;++i)
if (tr[x].s[i]) tr[tr[x].s[i]].fail=tr[tr[x].fail].s[i],q.push(tr[x].s[i]);
else tr[x].s[i]=tr[tr[x].fail].s[i];
}
}
int b[N+9];
void Query(char *c,int len){
int x=0,t;
for (int i=1;i<=len;++i){
x=tr[x].s[c[i]-'a'];t=tr[x].get;
++b[i-tr[t].deep+1];--b[i+1];
}
}
int n,m,len;
char c[N+9],tmp[N+9];
Abigail into(){
scanf("%d",&n);
scanf("%s",c+1);
scanf("%d",&m);
Build();
for (int i=1;i<=m;++i){
scanf("%s",tmp+1);
len=strlen(tmp+1);
Insert(tmp,len);
if (i%200==0){
Get_fail();
Query(c,n);
Build();
}
}
Get_fail();
Query(c,n);
}
Abigail outo(){
int ans=0;
for (int i=1;i<=n;++i){
b[i]+=b[i-1];
if (b[i]==0) ++ans;
}
printf("%d\n",ans);
}
int main(){
into();
outo();
return 0;
}