您的位置:首页 > Web前端 > JavaScript

[JSOI2012]玄武密码

2018-03-16 07:34 393 查看

题目大意:
  给定一个目标串$t(|t|\le10^7)$和$m(m\le10^5)$个模板串$s_i(|s_i|\le100)$,对于每个$s_i$,求$s_i$在$t$中出现过的最长前缀。

思路:
  先用所有的$s_i$建一个AC自动机,然后将$t$放进去匹配,标记经过的所有结点及其失配指针指向的结点。再将每个$s_i$放进去匹配,找到最深的有标记的位置。

#include<list>
#include<queue>
#include<cstdio>
#include<cctype>
#include<cstring>
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
const int L1=1e7+1,M=1e5,L2=101,S=4;
char t[L1],s[M][L2];
class AhoCorasick {
private:
std::queue<int> q;
bool val[M*L2],vis[M*L2];
int ch[M*L2][S],fail[M*L2];
int sz,new_node() {
return ++sz;
}
int idx(const char &c) const {
if(c=='N') return 0;
if(c=='E') return 1;
if(c=='W') return 2;
if(c=='S') return 3;
}
public:
void insert(const char s[]) {
for(register int i=0,p=0;s[i];i++) {
const int c=idx(s[i]);
p=ch

[c]?:ch[p][c]=new_node(); } } void get_fail() { for(register int c=0;c<S;c++) { if(ch[0][c]) q.push(ch[0][c]); } while(!q.empty()) { const int &x=q.front(); for(register int c=0;c<S;c++) { int &y=ch[x][c]; if(y) q.push(y); (y?fail[y]:y)=ch[fail[x]][c]; } q.pop(); } } void find(const char s[]) { for(register int i=0,p=0;s[i];i++) { for(register int q=p=ch[p][idx(s[i])];!vis[q];q=fail[q]) { val[q]=vis[q]=true; } } } int query(const char s[]) { for(register int i=0,p=0;s[i];i++) { if(!val[p=ch[p][idx(s[i])]]) return i; } return strlen(s); } }; AhoCorasick ac; int main() { const int n=getint(),m=getint(); scanf("%s",t); for(register int i=0;i<m;i++) { scanf("%s",s[i]); ac.insert(s[i]); } ac.get_fail(); ac.find(t); for(register int i=0;i<m;i++) { printf("%d\n",ac.query(s[i])); } return 0; }

[p] 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: