AC自动机(未完成)

不带入门!(以后有空可能会写?)

模板

ac自动机模板
给定n个单词,一篇文章,问有多少个单词在这篇文章中出现过

输入格式
第一行:一个整数n(n<=10000)

接下来n行,每行一个单词。保证单词长度<=50

最后一行:一个长度为m的字符串,表示这篇文章。m<=1000000

输出格式
一个整数,表示多少个单词出现过。

input

5
she
he
say
shr
her
yasherhs
output

3
数据规模与约定
hdoj 2222

时间限制:1s

空间限制:256MB

#include<bits/stdc++.h>
using namespace std;
struct tri_tree{int linkk[26],fail,endflag;}tr[600000];
int head,tail,q[600000],t,ans;
char s[1001000];
int read() { 
    bool flag=true; 
    int num=0;char c=getchar(); 
    for(;c<'0'||c>'9';c=getchar())if(c=='-') flag=false; 
    for(;c>='0'&&c<='9';c=getchar()) 
    num=(num<<3)+(num<<1)+c-48; 
    if(flag) return num; 
     else return -num; 
}
void add(){
    int node=0;
    for(int i = 0;i < strlen(s) ;++i){
        int c = s[i] - 'a';
        if( !tr[node].linkk[c] )
         tr[node].linkk[c] = ++t;
        node = tr[node].linkk[c]; 
    }
    tr[node].endflag++;
    return;
} 
void init(){
    int n = read();
    for(int i = 1;i <= n;++i) {
      scanf("%s",s);
      add();
     }
    return;
}
void AC(){
    head = 0;tail = 0;q[tail]=0;
    while(head <= tail){
        int now = q[head++];
        for(int i = 0;i < 26;++i){
            int node = tr[now].linkk[i] , Fail = tr[now].fail;
            if(node>0){
                if(!now) tr[node].fail = 0;
                 else tr[node].fail = tr[Fail].linkk[i];
                 q[++tail] = node;
            }
            else 
             if(!now)
              tr[now].linkk[i] = 0;
             else
              tr[now].linkk[i] = tr[Fail].linkk[i];
        }
    }
    return;
}
void find(){
    ans=0;
    int now=0;
    scanf("%s",s);
    int len=strlen(s);
    for(int i=0;i<len;++i)
    {
        int chindex=s[i]-'a';
        while(!tr[now].linkk[chindex]&&now!=0) now=tr[now].fail;
        now=tr[now].linkk[chindex];
        int temp=now;
        while(temp!=0&&tr[temp].endflag>-1)
        {
            ans+=tr[temp].endflag;
            tr[temp].endflag=-1;
            temp=tr[temp].fail;
        }    
    }
    printf("%d",ans);
    return; 
}
int main(){
    init();
    AC();
    find();
    return 0;
}

bzoj3940[Usaco2015 Feb]Censoring

描述
提交
自定义测试
题目描述
Farmer John has purchased a subscription to Good Hooveskeeping magazine for his cows, so they have plenty of material to read while waiting around in the barn during milking sessions. Unfortunately, the latest issue contains a rather inappropriate article on how to cook the perfect steak, which FJ would rather his cows not see (clearly, the magazine is in need of better editorial oversight).

FJ has taken all of the text from the magazine to create the string S of length at most 10^5 characters. He has a list of censored words t_1 … t_N that he wishes to delete from S. To do so Farmer John finds the earliest occurrence of a censored word in S (having the earliest start index) and removes that instance of the word from S. He then repeats the process again, deleting the earliest occurrence of a censored word from S, repeating until there are no more occurrences of censored words in S. Note that the deletion of one censored word might create a new occurrence of a censored word that didn’t exist before.

Farmer John notes that the censored words have the property that no censored word appears as a substring of another censored word. In particular this means the censored word with earliest index in S is uniquely defined.Please help FJ determine the final contents of S after censoring is complete.

FJ把杂志上所有的文章摘抄了下来并把它变成了一个长度不超过10^5的字符串S。他有一个包含n个单词的列表,列表里的n个单词 记为t_1…t_N。他希望从S中删除这些单词 。 FJ每次在S中找到最早出现的列表中的单词(最早出现指该单词的开始位置最小),然后从S中删除这个单词。他重复这个操作直到S中 没有列表里的单词为止。注意删除一个单词后可能会导致S中出现另一个列表中的单词

FJ注意到列表中的单词不会出现一个单词是另一个单词子串的情况,这意味着每个列表中的单词在S中出现的开始位置是互不相同的 请帮助FJ完成这些操作并输出最后的S

输入格式
The first line will contain S. The second line will contain N, the number of censored words. The next N lines contain the strings t_1 … t_N. Each string will contain lower-case alphabet characters (in the range a..z), and the combined lengths of all these strings will be at most 10^5. 第一行包含一个字符串S

第二行包含一个整数N

接下来的N行,每行包含一个字符串,第i行的字符串是t_i

输出格式
The string S after all deletions are complete. It is guaranteed that S will not become empty during the deletion process.

一行,输出操作后的S

样例数据
input

begintheescapexecutionatthebreakofdawn
2
escape
execution
output

beginthatthebreakofdawn
数据规模与约定
保证a,b≤109a,b≤109。

时间限制:1s1s
空间限制:256MB

这道题难度还是有一点的。

首先你得想到得用栈来维护一下答案以及每个时间你的位置。

其次如果每位寻找你都跳fail指针肯定是会TLE的,注意题目条件,一个串肯定不会是另一个串的子串。也就是说你不用每次都跳while循环。

想到这这道题差不多就能A了

#include<bits/stdc++.h>
using namespace std;
struct tri_tree{int linkk[26],fail,deep;bool endflag;}tr[600000];
int head,tail,q[600000],t,fa[600000],m,pl[600000];
char s[101000],c[101000],an[101000];
int read() { 
    bool flag=true; 
    int num=0;char c=getchar(); 
    for(;c<'0'||c>'9';c=getchar())if(c=='-') flag=false; 
    for(;c>='0'&&c<='9';c=getchar()) 
    num=(num<<3)+(num<<1)+c-48; 
    if(flag) return num; 
     else return -num; 
}
void add(){
    int node=0;
    int len=strlen(c);
    for(int i = 0;i < len ;++i){
        int cc = c[i] - 'a';
        if( !tr[node].linkk[cc] )
         tr[node].linkk[cc] = ++t,
         fa[ tr[node].linkk[cc] ] = node,
         tr[ tr[node].linkk[cc] ].deep = tr[node].deep + 1;
        node = tr[node].linkk[cc]; 
    }
    tr[node].endflag = true;
    return;
} 
void init(){
    scanf("%s",s);
    int n = read();
    for(int i = 1;i <= n;++i) {
      scanf("%s",c);
      add();
     }
    return;
}
void AC(){
    head = 0;tail = 0;q[tail]=0;
    while(head <= tail){
        int now = q[head++];
        for(int i = 0;i < 26;++i){
            int node = tr[now].linkk[i] , Fail = tr[now].fail;
            if(node>0){
                if(!now) tr[node].fail = 0;
                 else tr[node].fail = tr[Fail].linkk[i];
                 q[++tail] = node;
            }
            else 
             if(!now)
              tr[now].linkk[i] = 0;
             else
              tr[now].linkk[i] = tr[Fail].linkk[i];
        }
    }
    return;
}
void deletee(int &x,int v,int &pl){
    int temp=tr[v].deep;
    while(tr[v].deep) x=fa[x],v=fa[v];
    for(int i=pl,t=0;t<temp;--i,pl=i) 
     if(s[i]!=0) s[i]=0,t++;
    return;
}
void find(){
    int ans = 0;
    int now = 0;
    int len=strlen(s);
    for(int i = 0;i < len;++i){
        int c = s[i]-'a';
        now = tr[now].linkk[c];
        an[++ans]=c;
        pl[ans]=now;
            if(tr[now].endflag)
            {
             ans-=tr[now].deep;
             now=pl[ans];
            }
    }
    for(int i=1;i<=ans;++i)
     printf("%c",an[i]+'a');
    return; 
}
int main(){
    init();
    AC();
    find();
    return 0;
} 

猜你喜欢

转载自blog.csdn.net/a1035719430/article/details/79475489