标签:inpu 直接 过滤器 cstring kmp 字符 差分 ret 包括
Description
给定一些短串,要求你在一个长串中,将这些短串部分变为\(*\)
Input
第一行包括一个整数\(n\),表示短串的数量.
接下来的\(n\)行,为\(n\)个短串.
最后一行,为你需要变化的长串.
Output
一行,表示变化后的长串.
PS:长串会有中有各种字符,短串仅包含英文字符
样例输入
3
int
ing
kitty
Int is interesting! ~OwO~
样例输出
\(***\) is \(***\)erest\(***\)ing! ~OwO~
上面的一些输入输出中为全角,实际上为半角.
这题做法有很多啊,可以哈希,可以AC自动机,可以KMP.
这里讲一下KMP算法.
做法为\(KMP+\)差分.
首先需要将长串中的字母全部转为小写(大写).
\(isalpha\)吼啊
我们对每一个短串求出其\(next\)数组.再枚举这些串去和长串匹配.
但是一些位置会出问题.
比如
给定两个短串为\(GRE\)和\(eat\),长串为\(Great\)
则我们的长串要变成\(*****\)
因此引入了差分.
如果匹配上之后,我们直接对其左端点和右端点\(+1\)差分。
最终枚举的话,直接判断有无标记,如果有,则将当前位置变为\(*\)
然后直接输出即可.
代码
#include<cstdio>
#include<cctype>
#include<cstring>
#define R register
using namespace std;
char sta[150008],stb[150008];
int pos[150008],k,n,len;
struct cod
{
int nex[55],len;
char s[55];
}str[55];
char st[55],c;
inline char ch(char s)
{
if(!isalpha(s))return s;
if(s<='Z' and s>='A')s=s-'A'+'a';
return s;
}
int main()
{
scanf("%d",&n);
for(R int i=1;i<=n;i++)
{
scanf("%s",st+1);
str[i].len=strlen(st+1);
for(R int j=1;j<=str[i].len;j++)
str[i].s[j]=ch(st[j]);
str[i].nex[1]=0;k=0;
for(R int j=2;j<=str[i].len;j++)
{
while(str[i].s[k+1]!=str[i].s[j] and k)k=str[i].nex[k];
if(str[i].s[k+1]==str[i].s[j])k++;
str[i].nex[j]=k;
}
}
getchar();
while(c!='\n')
{
c=getchar();
if(c=='\n')break;
sta[++len]=c;
stb[len]=ch(c);
}
for(R int i=1;i<=n;i++)
{
k=0;
for(R int j=1;j<=len;j++)
{
while(k and str[i].s[k+1]!=stb[j])k=str[i].nex[k];
if(str[i].s[k+1]==stb[j])k++;
if(k==str[i].len)
{
pos[j-str[i].len+1]++;
pos[j+1]--;
}
}
}
for(R int i=1;i<=len;i++)
{
pos[i]+=pos[i-1];
if(pos[i])sta[i]='*';
printf("%c",sta[i]);
}
}
/*
2
GRE
eat
Great Britain
***** Britain
*/
标签:inpu 直接 过滤器 cstring kmp 字符 差分 ret 包括
原文地址:https://www.cnblogs.com/-guz/p/9829149.html