zoukankan      html  css  js  c++  java
  • 洛谷P3121 【[USACO15FEB]审查(黄金)Censoring (Gold)】

    双栈+AC自动机

    这题其实跟一道KMP算法的题有一些渊源,它就是这道题的简单板。

    Clear:
    给你两个串A,B,每次在B串中从左到右找串A,并将该子串删除,直到找不到为止,问你能删几次。

    样例输入:
    abc

    abcabcabaabcbccc

    样例输出:
    5

    思路:
    开一个栈,每次放入被匹配字符串的一个字符。如果当前栈中字符数量大于等于匹配串的长度,开始匹配,如果有一个单词匹配失败,break掉,继续放字符。

    #include<bits/stdc++.h>
    using namespace std;
    int lc,lb,cnt,flag,ans;
    char a[10000001];
    string b,c;
    int main()
    {
    	cin>>b>>c;
    	lb=b.size();
    	lc=c.size();
    	for(int i=0;i<lc;i++)
    	{
    		a[++cnt]=c[i];
    		if(cnt<b.size())
    		{
    			continue;
    		}
    		if(a[cnt]!=b[lb-1])
    		{
    			continue;
    		}
    		flag=0;
    		for(int i=cnt-lb+1,j=0;i<cnt;i++,j++)//匹配
    		{
    			if(a[i]!=b[j])
    			{
    				flag=1;//发现目标串,标记。
    				break;
    			}
    		}
    		if(!flag)
    		{
    			ans++;
    			cnt-=lb;//减长度
    		}
    	}
    	printf("%d
    ",ans);//输出
    	return 0;
    }
    

    那么经过这题的思考之后,加强版(就是这题)的思路也应该油然而生了——我们同样用栈做,一个栈命名为s2,用来表示当前节点跑到了AC自动机中的trie树哪里了,另一个栈s3,用来表示最后的字符串留下了原字符串的哪些位上的字符。

    如果发现当前这一个栈中的字符的后缀是单词,直接减去单词的长度(所以isword要存的是长度)。

    剩下就是输出了。

    友情提醒:在洛谷提交的话,末尾最好加个‘ ’。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    int cnt,s2[100010],s3[100010],n,wei,top;//s2是存root,s3是存剩下的。
    string s1,s;
    queue<int>q;
    struct data
    {
        int b[26],fail,isword;//isword用来存s.size。
    }a[1000001];
    void build(string t)//建trie树
    {
        int root=0;
        for(int i=0;t[i];i++)
        {
            int x=t[i]-'a';
            if(!a[root].b[x])a[root].b[x]=++cnt;
            root=a[root].b[x];
        }
        a[root].isword=t.size();
    }
    int main()
    {
        cin>>s;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            cin>>s1;
            build(s1);
        }
        for(int i=0;i<26;i++)
        {
            if(a[0].b[i])
            {
                q.push(a[0].b[i]);
            }
        }
        while(!q.empty())
        {
            int k=q.front();
            q.pop();
            for(int i=0;i<26;i++)
            {
                if(a[k].b[i])
                {
                    a[a[k].b[i]].fail=a[a[k].fail].b[i];
                    q.push(a[k].b[i]);	
                }else{
                	a[k].b[i]=a[a[k].fail].b[i];
                } 
            }
        }
        int root=0;
        //双栈走起
        while(wei<s.size())
        {
        	int x=s[wei]-'a';
        	root=a[root].b[x];
        	s2[++top]=root;
        	s3[top]=wei;
        	if(a[root].isword)
        	{
        		top-=a[root].isword;
        		if(top==0)
        		{
        			root=top;
        		}else{
        			root=s2[top];
        		}
        	}
        	wei++;
        }
        for(int i=1;i<=top;i++)
        {
        	cout<<s[s3[i]];
        }
        putchar('
    ');
        return 0;
    }
    

    QAQAQAQ

  • 相关阅读:
    Django ORM多表操作
    Django 单表查询作业-笔记
    python 2 编码问题
    HTML-Bootstrap下载和基本使用
    Django ORM单表操作之增删改查
    Django ORM简介和单表创建的设置和过程
    Django --总结 之URL路由控制 视图相应,视图请求,和模板语法
    Django URL控制器
    JAVA编程
    UMI 的原理分析带有 UMI 的数据
  • 原文地址:https://www.cnblogs.com/2017gdgzoi44/p/11323210.html
Copyright © 2011-2022 走看看