传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2938
我会拼AC自动机服不服:AhoCorasickAutoMata
就这么厉害
病毒代码,总长不超过30K……明显AC自动机吗……建出来建出来
题目要求一个无限长的安全子串,为什么能无限长呢,也就是说它在AC自动机上匹配模板永远匹配不到
等价于永远走不到一个val值为1的节点
那么只要判断AC自动机上是否存在一个由val=0的节点相连形成的环就可以了,加一个dfs即可
代码如下
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define red(i, a, b) for(int i = (a); i >= (b); i--)
#define ll long long
const int maxn = 30100;
const int sigmasize = 2;
char s[maxn];
int n;
struct AhoCorasickAutoMata{
int sz;
int ch[maxn][3];
int val[maxn],f[maxn],ins[maxn],vis[maxn],last[maxn];
AhoCorasickAutoMata() { sz=1; memset(ch[0], 0, sizeof(ch[0])); }
int idx(char c) { return c-'0'; }
void insert(char* s,int v){
int u = 0, n = strlen(s);
rep(i, 0, n-1) {
int c = idx(s[i]);
if(!ch[u][c]) {
memset(ch[sz], 0, sizeof(ch[sz]));
val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u] = v;
}
void getfail() {
queue<int> q;
f[0] = 0;
rep(c, 0, sigmasize-1){
int u = ch[0][c];
if(u) { f[u] = 0; q.push(u); last[u] = 0; }
}
while(!q.empty()) {
int r = q.front(); q.pop();
rep(c, 0, sigmasize-1) {
int u = ch[r][c];
if(!u) {
ch[r][c] = ch[f[r]][c];
continue;
}
q.push(u);
int v = f[r];
while(v && !ch[v][c]) v = f[v];
f[u] = ch[v][c];
last[u] = val[f[u]] ? f[u] : last[f[u]];
val[u] |= val[ch[v][c]];
}
}
}
bool dfs(int x) {
ins[x] = 1;
rep(i, 0, 1) {
int v = ch[x][i];
if(ins[v]) return 1;
if(vis[v] || val[v]) continue;
vis[v] = 1;
if(dfs(v)) return 1;
}
ins[x] = 0;
return 0;
}
}ac;
int main() {
scanf("%d", &n);
char ch = getchar();
rep(i, 1, n){
scanf("%s", s);
ac.insert(s, 1);
}
ac.getfail();
if (ac.dfs(0)) printf("TAK\n");
else printf("NIE\n");
return 0;
}
新代码风格持续养成中==