【题解】「USACO2015FEB」Censoring (Silver银组)(KMP)

题面

【题目描述】
FarmerJohnFarmer John为他的奶牛们订阅了GoodHooveskeepingGood Hooveskeeping杂志,因此他们在谷仓等待挤奶期间,可以有足够的文章可供阅读。不幸的是,最新一期的文章包含一篇关于如何烹制完美牛排的不恰当的文章,FJFJ不愿让他的奶牛们看到这些内容。

FJFJ已经根据杂志的所有文字,创建了一个字符串 $S $( SS 的长度保证不超过 10610^6 ),他想删除其中的子串 TT ,他将删去 SS 中第一次出现的子串 TT,然后不断重复这一过程,直到 SS 中不存在子串TT

注意:每次删除一个子串后,可能会出现一个新的子串 TT (说白了就是删除之后,两端的字符串有可能会拼接出来一个新的子串 TT)。

【输入格式】
第一行是字符串 SS ,第二行输入字符串 TT ,保证 SS 的长度大于等于 T 的长度, SSTT 都只由小写字母组成。

【输出格式】
输出经过处理后的字符串,保证处理后的字符串不会为空串

算法分析

单模式串的匹配通常采用KMP算法。
但是本题在匹配的同时,会进行删除,但是删除的部分肯定是已经匹配了的部分,所以可以用两个栈来记录。
一个栈st[],记录未匹配成功的字符
一个栈num[],记录每个字符S[i]对应匹配的T[j]中的j
这样,当匹配成功后,可以对删除子串的前一个S[i],找到对应的T[j],继续执行KMP算法。

参考程序

#include<bits/stdc++.h>
using namespace std;
const int N=1000005;
char S[N],T[N]; 
int nxt[N];
char st[N]; //栈 
int top;
int num[N];
void pre()  //预处理nxt数组 
{
    int j;
    nxt[1]=j=0;     //初始化 
    int lent=strlen(T+1);
    for(int i=1;i<lent;i++)      
    {
        while(j>0&&T[i+1]!=T[j+1])   j=nxt[j];
        if(T[j+1]==T[i+1])  j++;
        nxt[i+1]=j; 
    } 
}
void kmp()
{
    int lent=strlen(T+1);
    int lens=strlen(S+1);
    int j=0;
    for(int i=0;i<lens;i++)
    {
        while(j>0&&S[i+1]!=T[j+1])   j=nxt[j];
        if(S[i+1]==T[j+1])  j++;
        st[++top]=S[i+1];       //未匹配的入栈 
        num[top]=j;             //记录每个i对应的j 
        if(j==lent)     //匹配成功,则将整个匹配部分出栈 
        {
            top-=lent;
            if(top==0) j=0; //栈空 
            else j=num[top]; //从当前st[top]字符对应的j,即num[top],继续往后匹配 
        }
    }
    for(int i=1;i<=top;i++)
        printf("%c",st[i]);
}
int main()
{
    scanf("%s%s",S+1,T+1);
    pre();
    kmp();
    return 0;
} 
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读