BZOJ3942
分析:一个个匹配,不过中途记录一下当前的fail, 这样的话删除一部分,也可以回溯到那时的状态
/***********************************************
Author :lzs
Created Time :2018年10月23日 星期二 20时08分00秒
File Name :bzoj_3942.cpp
************************************************/
#include <bits/stdc++.h>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <string>
#include <math.h>
#include <stack>
#include <vector>
#include <queue>
#include <set>
#include <map>
using namespace std;
#define rep(i, l, r) for(int i = l; i < r; i++)
#define per(i, r, l) for(int i = r; i >= l; i--)
#define dbgln(...) cerr<<"["<<#__VA_ARGS__":"<<(__VA_ARGS__)<<"]"<<"\n"
#define dbg(...) cerr<<"["<<#__VA_ARGS__":"<<(__VA_ARGS__)<<"]"
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const int N = (int) 1e6 + 11;
const int M = (int) 1e6 + 11;
const int MOD = (int) 1e9 + 7;
const int INF = (int) 0x3f3f3f3f;
const ll INFF = (ll) 0x3f3f3f3f3f3f3f3f;
/*-----------------------------------------------------------*/
char s[N], t[N];
int nxt[N];
void getnxt(char *s){
int i, j;
j = nxt[0] = -1;
i = 0; int n = strlen(s);
while(i < n){
while(j != -1 && s[i] != s[j]) j = nxt[j];
++j; ++i;
if(s[j] == s[i]) nxt[i] = nxt[j];
else nxt[i] = j;
}
}
int fail[N], top;
char ans[N];
int main(){
scanf("%s%s", s, t);
stack<char>st;
getnxt(t);
int j = 0; int lent = strlen(t);
for(int i = 0; s[i]; ){
ans[++top] = s[i];
while(j != -1 && t[j] != s[i]) j = nxt[j];
++j; ++i;
fail[top] = j;
if(j == lent) {
top -= lent;
j = fail[top];
}
}
for(int i = 1; i <= top; i++) putchar(ans[i]);putchar('\n');
return 0;
}
BZOJ3940
和上一道思路一样,匹配中途维护一下当前的fail值,这样删除后,才可以回溯到原来的状态
一个模式串用kmp就可以,但是多个模式串肯定要用ac自动机了
#include<bits/stdc++.h>
using namespace std;
const int N = (int)1e5 + 11;
queue<int>q;
struct AC_{
// 字典树相关,分别表示: 存储图,标记单词尾,总节点个数
int c[N][26], val[N], cnt;
int len[N];
int fail[N]; // 失配转移
int f[N];
char ans[N]; int top;
void ins(char *s){
int le=strlen(s);int now=0;
for(int i=0;i<le;i++){
int v=s[i]-'a';
if(!c[now][v])c[now][v]=++cnt;
now=c[now][v];
}
val[now]++; //标记 是一个单词尾
len[now] = le;
}
void build(){ // fail的建立, 注意fail建立之后 字典树中的指向已经变了
// 和根节点相连的加入队列中
for(int i=0;i<26;i++) if(c[0][i])fail[c[0][i]]=0,q.push(c[0][i]);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<26;i++)
if(c[u][i]) fail[c[u][i]]=c[fail[u]][i],q.push(c[u][i]);//如果u有i这个分支
else c[u][i]=c[fail[u]][i]; // 可以跳很多
}
}
void query(char *s){
int le=strlen(s);
int now=0;
for(int i=0;i<le;i++){
ans[++top] = s[i];
now=c[now][s[i]-'a'];
// val[t] = -1 表示已经访问过, t = 0表示到了根节点
f[top] = now;
if(val[now]){ //核心!因为模式串之间不会有互为子串,所以不用沿着fail下找
// 这样才不会TLE
top -= len[now];
now = f[top];
continue;
}
}
for(int i = 1; i <= top; i++) putchar(ans[i]);putchar('\n');
}
}AC;
int n;char p[1000005];
char s[N];
int main(){
scanf("%s", p);
int n; scanf("%d" ,&n);
for(int i = 0; i < n; i++){
scanf("%s", s);
AC.ins(s);
}
AC.build();
AC.query(p);
return 0;
}