您的位置:首页 > 其它

BZOJ 1212 [HNOI2004] L语言 AC自动机+DP

2017-01-17 09:18 323 查看
题目大意:给出n个模式串,接着给出m个主串,求每个主串中的一个最长前缀使得其能被分割成若干个模式串。

Trie树上暴力时间复杂度O(1M*10*20),过亿应该就很卡了吧…但是也能过,不过写AC自动机稳一点吧。

设状态f(i)为长度为i的前缀是否能通过几个模式串表示出来。模式串建成AC自动机,结点上记录这个串的长度,用主串在上面跑,若匹配到了一个长度为j的串,则f(i) |= f(i-j).

需要注意的是,一个结点中本身没有串但是在它的fail指针中可能含有串,所以在getFail中需要用fail指针的val值更新自己的val值。因为是bfs,当前点表示的串一定是目前最长的,而跳fail是往前跳,所以取max就一定不会出现本身代表一个串却被更新的情况。

#include <cstdio>
#include <cstring>
#include <queue>
#define Max(a,b) (a>b?a:b)
using namespace std;
struct Node {
Node *ch[26],*nxt;
int val;
Node():nxt(0x0),val(0) {memset(ch,0,sizeof ch);}
}*root=new Node();
int n,m;
char s[1000005];
bool jud[1000005];
void Insert() {
int len=strlen(s);
Node* o=root;
for(int i=0;i<len;i++) {
int z=s[i]-'a';
if(!o->ch[z]) o->ch[z]=new Node();
o=o->ch[z];
}
o->val=len;
return ;
}
void getFail() {
static queue<Node*> q;
Node* o=root;
for(int i=0;i<26;i++)
if(o->ch[i]) q.push(o->ch[i]) , o->ch[i]->nxt=o;
else o->ch[i]=o;
while(!q.empty()) {
o=q.front(); q.pop();
for(int i=0;i<26;i++)
if(o->ch[i]) q.push(o->ch[i]) , o->ch[i]->nxt=o->nxt->ch[i];
else o->ch[i]=o->nxt->ch[i];
Node* tmp=o->nxt;
while(tmp!=root && !tmp->val) tmp=tmp->nxt;
o->nxt=tmp;
o->val=Max(o->val,tmp->val);
}
return ;
}
void Match() {
Node* o=root;
int len=strlen(s+1);
for(int i=1;i<=len;i++) {
int z=s[i]-'a';
o=o->ch[z];
if(o->val) {
Node* tmp=o;
while(tmp!=root) jud[i]|=jud[i-tmp->val] , tmp=tmp->nxt;
}
}
return ;
}
int main() {
scanf("%d%d",&n,&m);
while(n--) scanf("%s",s) , Insert();
getFail();
while(m--) {
memset(jud,false,sizeof jud); jud[0]=true;
scanf("%s",s+1);
Match();
int i;
for(i=strlen(s+1);i;i--) if(jud[i]) break;
printf("%d\n",i);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: