Censoring(Bzoj3942)

 

试题描述
给出两个字符串 S 和 T,长度均小于10^6,每次从前往后找到 S 的一个子串 A=T 并将其删除,空缺位依次向前补齐,重复上述操作多次,直到 S 串中不含 T串。输出最终的 S 串。
输入
第一行包含一个字符串 S,第二行包含一个字符串 T。
输出
输出处理后的 S 串。
输入示例
whatthemomooofun
moo
输出示例
whatthefun
其他说明
数据范围与提示
对于全部数据,1≤∣T∣≤∣S∣≤10^6,保证字符串中只出现小写字母。

正解应该是kmp+栈,还是手写的比较好维护,因为要大量删除

我们不难看出在写完kmp的板子之后做一点小小的处理就可以了,每次找到匹配的之后,不用去和主串比较

只需要与栈末尾的串相比就可以了,在对比过程中,我们还需要维护一个在栈中的nxt数组(动态维护即可)

下面给出代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
inline int rd(){
    int x=0,f=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
inline void write(int x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
    return ;
}
char s[1000006];
char a[1000006];
int n,m;
int p[1000006];
int nxt[1000006];
char s1[1000006];
int total=0;
void pre(){
    int j=0;
    for(int i=1;i<m;i++){
        j=p[i];
        while(j>0&&a[i+1]!=a[j+1]) j=p[j];
        if(a[i+1]==a[j+1]) j++;
        p[i+1]=j;
    }
    return ;
}
void kmp(){
    int j=0;
    for(int i=0;i<n;i++){
        total++;
        s1[total]=s[i+1];//入栈 
        while(j>0&&s1[total]!=a[j+1]) j=p[j];
        if(a[j+1]==s1[total]) j++;
        nxt[total]=j;//维护在栈中失配后跳到哪里 
        if(j==m){
            total-=m;//删除操作,手写就是好 
            j=nxt[total];
        }
    }
    return ;
}
int main(){
    scanf("%s",s+1);
    scanf("%s",a+1);
    n=strlen(s+1);
    m=strlen(a+1);
    pre();
    kmp();
    for(int i=1;i<=total;i++) printf("%c",s1[i]);
    return 0;
}

 

posted @ 2018-09-26 20:23  Bruce--Wang  阅读(430)  评论(0编辑  收藏  举报