[JSOI2012]玄武密码
题目大意:
给定一个目标串$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[p][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; }
- [BZOJ4327]JSOI2012 玄武密码(AC自动机)
- 4327: JSOI2012 玄武密码[SAM]
- BZOJ 4327 【JSOI 2012】 玄武密码 AC自动机+dfs
- 【BZOJ4327】JSOI2012 玄武密码 AC自动机
- 【bzoj4327】【JSOI2012】【玄武密码】【AC自动机】
- [BZOJ]4327 [JSOI2012] 玄武密码 AC自动机
- [BZOJ4327] JSOI2012玄武密码
- 【BZOJ4327】【JSOI2012】玄武密码
- BZOJ[4327]JSOI2012 玄武密码 AC自动机
- BZOJ4327 JSOI2012玄武密码(AC自动机)
- BZOJ 4327: JSOI2012 玄武密码
- 【JSOI2012】【BZOJ4327】玄武密码
- BZOJ 4327 JSOI2012 玄武密码(后缀自动机)
- BZOJ_4327_JSOI2012 玄武密码_AC自动机
- 玄武密码(bzoj4327)(JSOI2012)
- [BZOJ4327]-[JSOI2012]玄武密码-AC自动机
- BZOJ4327 : JSOI2012 玄武密码
- bzoj 4327: JSOI2012 玄武密码 (AC自动机)
- BZOJ-4327:JSOI2012 玄武密码(AC自动机模板题)
- FFT 【JSOI2012】bzoj4332 分零食