P3121 [USACO15FEB]审查(黄金)Censoring (Gold)

吐槽

数据太水了吧,我AC自动机的trie建错了结果只是RE了两个点,还以为数组开小了改了好久

思路

看到多模板串,字符串匹配,且模板串总长度不长,就想到AC自动机
然后用栈维护当前的字符串位置,如果匹配到了,就从栈里逐个弹出对应的字符,并且回溯到匹配这个单词之前的节点
s每个字符最多会被出栈和入栈各两次,复杂度是\(O(n+m)\)的

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
int trie[410000][26],Nodecnt=0,fail[410000],mark[410000],root,len[410000],n;
char s[410000],t[410000];
void insert(char *s,int len,int cnt){
    int o=root;
    for(int i=1;i<=len;i++){
        if(!trie[o][s[i]-'a'])
            trie[o][s[i]-'a']=++Nodecnt;
        o=trie[o][s[i]-'a'];
    }
    mark[o]=cnt;
}
void build_AC(void){
    queue<int> q;
    for(int i=0;i<26;i++){
        if(trie[root][i]){
            fail[trie[root][i]]=root;
            q.push(trie[root][i]);
        }
    }
    while(!q.empty()){
        int x=q.front();
        q.pop();
        for(int i=0;i<26;i++){
            if(trie[x][i]){
                fail[trie[x][i]]=trie[fail[x]][i];
                q.push(trie[x][i]);
            }
            else{
                trie[x][i]=trie[fail[x]][i];
            }
        }
    }
}
struct SNode{
    int num;
    char c;
};
stack<char> S2;
stack<SNode> S1;
void query(void){
    int o=root;
    int mid=0;
    while(S2.size()){
        // printf("%d %d\n",++mid,S1.size());
        char c=S2.top();
        S2.pop();
        o=trie[o][c-'a'];
        if(!mark[o])
            S1.push((SNode){o,c});
        else{
            // printf("begin\n");
            int p=o;
            for(int i=1;i<=len[mark[p]];i++){
                if(S1.size())
                    o=S1.top().num;
                else{
                    o=root;
                    break;
                }
                if((!S1.empty())&&i<len[mark[p]])
                    S1.pop();
                else if(i<len[mark[p]]){
                    o=root;
                    break;
                }
            }
        }
    }
}
void print(void){
    char c=S1.top().c;
    S1.pop();
    if(!S1.empty())
        print();
    putchar(c);
}
int main(){
    // freopen("testdata (5).in","r",stdin);
    // freopen("test.out","w",stdout);
    scanf("%s",s+1);
    int lens=strlen(s+1);
    // printf("lens=%d\n",lens);
    // _sleep(1000);
    for(int i=lens;i>=1;i--)
        S2.push(s[i]);
    // int g=1;
    // for(;g<=lens;g++)
    //     if(s[g]!='a')
    //         break;
    // printf("sa=%d\n",g-1);
    // _sleep(1000);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",t+1);
        len[i]=strlen(t+1);
        // printf("len[%d]=%d\n",i,len[i]);
        // _sleep(1000);
        insert(t,len[i],i);
    }
    build_AC();
    query();
    // printf("ok\n");
    print();
    printf("\n");
    return 0;
}

原文地址:https://www.cnblogs.com/dreagonm/p/10454480.html

时间: 2024-10-09 05:43:45

P3121 [USACO15FEB]审查(黄金)Censoring (Gold)的相关文章

洛谷 P3121 [USACO15FEB]审查(黄金)Censoring (Gold) 【AC自动机+栈】

这个和bzoj同名题不一样,有多个匹配串 但是思路是一样的,写个AC自动机,同样是开两个栈,一个存字符,一个存当前点在trie树上的位置,然后如果到了某个匹配串的末尾,则弹栈 #include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int N=100005; int n,t[N],top; char a[N],b[N],s

LuoguP3121 [USACO15FEB]审查(黄金)Censoring (Gold)【Hash做法】By cellur925

题目传送门 其实这题正解是AC自动机的,字符串哈希吸氧才能过的,但是我太菜了不会...只能先用哈希苟了. 在扫描单词的时候首先把各个单词的哈希值和长度存起来.然后按照长度从小到大将各单词排序.而那个长长的字符串呢,我们就把它一点一点往栈里塞,够最小长度单词的长度时,我们就比较下,这样反复下去.如果遇到相同的字符串,就把他们弹出. 这个思路最巧妙的一点感觉就是用栈了.我自己写哈希的时候遇到删除的情况就布吉岛怎么搞了qwq. 这里的哈希值不能预处理出来的,而是动态维护的.因为有可能会删掉子串.所以只

luogu_P3121 [USACO15FEB]审查(黄金)Censoring (Gold)

栈模拟,哈希 #include<iostream> #include<cstdio> #define ri register int #define u unsigned long long namespace opt { inline u in() { u x(0),f(1); char s(getchar()); while(s<'0'||s>'9') { if(s=='-') f=-1; s=getchar(); } while(s>='0'&&am

「USACO15FEB」Censoring (Silver) 审查(银) 解题报告

题面 就是让你--在字符串A中,如果字符串B是A的子串,那么就删除在A中第一个出现的B,然后拼接在一起,一直重复上述步骤直到B不再是A的子串 |A|\(\le 10^6\) 思路: KMP+栈 1.由于是两个字符串匹配的问题,当然一下子就会想到KMP 2.由于是删去一段区间,很多人第一反应会想到链表,但是在这里,其实删除了一段后,对之前是没有影响的,并且,一定是从后往前删除,所以,更优的存储结构应该是栈. 3.有人会问,为什么删去对前面没有影响,这就根据KMP的原理,做到i这个位置的结果就是最优

AC自动机总结

AC自动机总结 自动机的概念: 自动机又称有限状态机,是从初始状态不断接受输入,根据输入数据和当前状态跳转到下一状态的一种机器. AC自动机可以实现多串匹配单串.复杂度是\(O(n+m)\),也就是匹配串长+模式串总长. AC自动机匹配失配时,类似KMP算法的next数组,AC自动机上有fail指针可以跳到下一个应该进行匹配的状态. fail指针的一般定义是:沿着父亲的fail指针一直向上跳,直到跳到某一个节点,这个节点拥有与自己相同字母的子节点,那么fail指针就指向这个相同字母的子节点. 一

nullcon HackIM 2016 -- Programming Question 2

Your simple good Deeds can save you but your GREED can kill you. This has happened before. This greedy person lived a miserable life just for the greed of gold and lust. You must know him, once you know him, you must reach his capital and next clues

解读刘强东关于人才的两个标准和5个层次

导读:"纽约当地时间5月22日上午10点左右,纳斯达克一楼演播厅,西装革履的刘强东上市致辞的时候,张口就是"这是京东人--",他马上意识到自己的错误,改为"先生们.女士们",全场笑了起来."这段话来源于网络小道消息,搞得好像就在刘强东身边站着似的,权当花絮,不知道真假.下面想讲的是这两天发布于各大媒体,关于京东上市前夕,刘强东与柳传志.李彦宏.雷军等大佬们的闭门交流实录,应该是真的.交流中刘强东说到了对人才的2个标准和5个层次,其中对5个层次有形

P4824 [USACO15FEB]Censoring (Silver) 审查(银)

传送门 一个串的匹配肯定考虑KMP 那就暴力KMP 记录一下到每个字符时匹配的位置 找到一个符合的串就标记然后暴力回跳 感觉好像太暴力了... #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int N=1e6+7; char ch[N],a[N]; int f[

贪心 洛谷P2870 [USACO07DEC]最佳牛线,黄金Best Cow Line, Gold

[USACO07DEC]最佳牛线,黄金Best Cow Line, Gold 题目描述 FJ is about to take his N (1 ≤ N ≤ 30,000) cows to the annual"Farmer of the Year" competition. In this contest every farmer arranges his cows in a line and herds them past the judges. The contest organ