CF533F Encoding 题解 (2)

  思路来自 【题解】Codeforces533F. Encoding 按字符分解,AC自动机 。其实与哈希匹配思想是一致的,都是想要找到一种方式可以做到对于每个起点 \(i\) ,进行 \(26\) 次复杂度只有 \(\mathcal O(1)\) 的判断。我们把 \(T\) 串分成 \(26\)\(01\) 串(不计入全 \(0\) 串),构建AC自动机。再将 \(S\) 串分成 \(26\)\(01\) 串,在AC自动机上作匹配,每次匹配到一个 \(T\) 串末尾,就在该位置标记匹配的字符,对于某个 \(i\) ,要求 \(T\)\(26\) 个字符 \(j\) 都能被匹配到末尾(除 \(j\)\(0\) 串外),才说明该段和 \(T\) 匹配。例如:

原字符串 \(a\)\(01\)\(b\)\(01\)\(c\)\(01\)
\(S\)   \(abcab\)   \(1~0~0~1~0\)   \(0~1~0~0~1\)   \(0~0~1~0~0\)  
\(T\)   \(acbac\)   \(1~0~0~1~0\)   \(0~0~1~0~0\)   \(0~1~0~0~1\)  

  这里 \(S\)\(a\) 串会匹配到AC自动机上对应 \(T\)\(a\) 串末端, \(S\)\(b\) 串会匹配到AC自动机上对应 \(T\)\(c\) 串末端, \(c\) 串会匹配到AC自动机上对应 \(T\)\(b\) 串末端,其他全为 \(0\) 的串不插入AC自动机,所以 \(S\)\(T\) 是匹配的。

AC自动机构建复杂度是 \(\mathcal O (26*n)\) 的,匹配时无需暴力跳fail,对于 \(26\) 个串的匹配也是 \(\mathcal O (26*n)\)

\(Code:\) #include <bits/stdc++.h> using namespace std; const int N = 2e5 + 5; int sl,tl,tt[N],en[N*26], match[27]; bool has[27]; char s[N],t[N]; vector<int>ans; int trie[N*26][2],cnt,fail[N*26],now[26]; void insert(int o){ int now = 0; for (int i = 1,c; i <= tl;i++){ c = tt[i]; if(trie[now][c] == 0) trie[now][c] = ++cnt; now = trie[now][c]; } en[now] = o; } void build(){ queue<int> q; for (int i = 0; i < 2;i++) if(trie[0][i]) q.push(trie[0][i]); while(!q.empty()){ int now = q.front();q.pop(); for (int i = 0; i < 2;i++){ if(trie[now][i]){ q.push(trie[now][i]); fail[trie[now][i]] = trie[fail[now]][i]; }else trie[now][i] = trie[fail[now]][i]; } } } int main() { scanf("%d %d %s %s",&sl,&tl,s+1,t+1); memset(en,-1,sizeof en); for(int j = 0;j < 26;j++){ for(int i = 1; i <= tl; i++) has[j] |= tt[i] = (t[i] == j + 'a'); if(has[j]) insert(j); //不是全0串才插入AC自动机 } build(); for(int i = 1;i <= sl;i++){ int flag = 0; memset(match,-1,sizeof match); for(int j = 0;j < 26;j++){ int c = s[i]-'a'; now[j] = trie[now[j]][c == j]; if(en[now[j]] != -1) match[en[now[j]]] = j;//记录T末端字符en[now[j]]匹配到S的字符j } for(int j = 0;j < 26;j++) if(has[j]){ if(match[j] == -1) {flag = 1;break;} int y = match[j]; //在T串同时含j,y的情况下,match[j]=y,match[y]=j才满足变换后匹配 if(match[y] != j && has[y]) {flag = 1;break;} } if(!flag) ans.push_back(i-tl+1); } printf("%d\n",ans.size()); for(auto it : ans) printf("%d ",it); return 0; }

  这道题可以用多种算法尝试解决,是一道很全面的题目。各算法运行结果如下(空间换时间了):

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwyzjg.html