1. 程式人生 > >BZOJ2938: [Poi2000]病毒(AC自動機)

BZOJ2938: [Poi2000]病毒(AC自動機)

for exit pty zoj %d () ora get color

Orz wlp 5min講完後綴數組

題意

給出$n$個0, 1串

問是否可以構造出一個無限長的字符串使其不包含任意串

Sol

剛開始我試圖假裝自己不知道這是個AC自動機的題然後來做。發現根本不可能qwq。

如果知道這題可以用AC自動機的話就好做很多了吧。

考慮我們構造的串中哪些子串不能出現。

1、給出的這$n$個串顯然不能出現—>本身

2、包含這個$n$個串的串顯然不能出現—> fail樹

因此我們在每個串結束的地方打上標記,同時如果一個串的fail樹上任意節點被打過標記,那麽這個節點一定是不能訪問的。

那最後怎麽統計答案呢?

考慮無限長的串一定可以被表示成某個串repeat~repeat~repeat~

所以我們從根節點開始,判斷是否能形成環就行了。

10min寫完沒調1Ahhh

#include<cstdio>
#include<queue>
#include<cstring>
#include<cstdlib>
using namespace std;
const int MAXN = 1e6 + 10, B = 2;
int N;
int ch[MAXN][2], fa[MAXN], fail[MAXN], flag[MAXN], tot = 0, root = 0;
char s[MAXN];
void insert(char
*s) { int N = strlen(s + 1), now = root; for(int i = 1; i <= N; i++) { int nxt = s[i] - 0; if(!ch[now][nxt]) ch[now][nxt] = ++tot; now = ch[now][nxt]; } flag[now] = 1; } void GetFail() { queue<int> q; for(int i = 0; i < B ;i++)
if(ch[root][i]) fail[ch[root][i]] = root, q.push(ch[root][i]); while(!q.empty()) { int p = q.front(); q.pop(); for(int i = 0; i < B; i++) { if(ch[p][i]) fail[ch[p][i]] = ch[fail[p]][i], flag[ch[p][i]] |= flag[fail[ch[p][i]]], q.push(ch[p][i]); else ch[p][i] = ch[fail[p]][i]; } } } int f[MAXN], vis[MAXN]; void dfs(int x) { f[x] = 1; for(int i = 0; i < B; i++) { if(f[ch[x][i]] == 1) {puts("TAK"); exit(0);} else if(!flag[ch[x][i]] && f[ch[x][i]] != 2) dfs(ch[x][i]); } f[x] = 2; } int main() { scanf("%d", &N); for(int i = 1; i <= N; i++) { scanf("%s", s + 1); insert(s); } GetFail(); dfs(root); puts("NIE"); return 0; } /* 3 011 11 00000 */

BZOJ2938: [Poi2000]病毒(AC自動機)