【Hash\KMP\线段树】文明的复兴

文明的复兴

(words.pas/in/out)

Problem

战神Prince&Gush回归了,但许多原先的上层精灵越来越不安分。他们无法忍受失去权力的空虚感,开始重新寻找新的途径获取权利。他们直率急躁的领导人King_Bette开始公开抨击权威,并散布谣言。 权利的统治需要统一,需要强硬,被逼无奈下正义的领袖开始收缴反动的资料,清除世界的毒瘤,借以踏上快速发展之路。

不良信息指的是一组单词,每个单词均为不良信息。不良信息文本是指包含一系列的单词,且其中包含有不良信息。发布信息者经常在单词中加些字母以外的字符以搅乱正义的视线,于是Prince想请你为他写一个能够将这些不良信息屏蔽掉的工具。但是为了尽量降低误删率,他提出了下面一个要求:你只需要将字母完全匹配的单词屏蔽掉即可。

例如:

sex为不良信息时,sex8,sex$,se#x均为不良信息sexx 则不属于不良信息.

 

Input

第一行为一个正数k <= 10000,表示有k个需要被屏蔽的词语,均为小写字母。

以下k行每行一个单词。

最后一行为输入需要处理的文本(文本长度<=100000),单词与单词之间空格分开且所有字母为小写字母。

Output

输出一行和输入格式一致的文本,被屏蔽的单词的字母以*代替原字母。

Sample Input

1

sex

sex sex8 sex$ s&&ex sexx aaa bbb

 

Sample Output

*** ***8 ***$ *&&** sexx aaa bbb



这道题题目描述极为不清晰。如果按照我的理解,这就该是一道好题,但是按照出题者的意思,这只是一道水题。


出题者的意思是一个单词必须找到和它完全匹配的,才能够和谐掉。如这组数据:

2

sex fuck

sex&&fuck are both about sex

答案是sex&&fuck are both about ***


而题意不清晰,让很多人以为应该是:

***&&**** are both about ***。


因此按照出题者的意思。只需要hash映射就完了。

#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <set>
using std::string;
using std::set;

set<string> hash;
string source;
char src[100010];
char str[100010];

int main()
{
	freopen("words.in","r",stdin);
	freopen("words.out","w",stdout);

	long k;
	scanf("%ld",&k);

	for (long i=1;i<k+1;i++)
	{
		long len = 0;
		long i = 0;
		scanf("%s",src+1);
		while (src[++len])
			src[++i] = src[len];
		src[++i] = 0;
		source = string(src+1);
		hash.insert(source);
	}

	while (scanf("%s",src+1)!=EOF)
	{
		long i = 0;
		long len = 0;
		while (src[++len])
			if (isalpha(src[len]))
				str[++i] = src[len];
		str[++i] = 0;
		source = string(str+1);
		if (hash.find(source)!=hash.end())
		{
			for (i=1;i<len;++i)
			{
				if (isalpha(src[i]))
					printf("*");
				else
					printf("%c",src[i]);
			}
		}
		else
		{
			printf("%s",src+1);
		}
		printf(" ");
	}

	return 0;
}


而按照较为合理的解释来做的话。严重超时。但是它确实更合理。

考虑到可能出现这种情况:

2

sex exchange

sexchange

应该整个单词都会被和谐掉,所以设计出以下方法:

先把原串合为一个字符串,把Kmp稍作改造,如果遇到原串中出现了符号,且模式串还未匹配完毕,则只修改原串的指针。如果匹配成功一次的话,则用线段树标记一次,并将模式串指针归零。


#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>

void next_init(char *words,long lenw,long *next)
{
	long k = 0;
	long j = 1;
	while (j < lenw+1)
	{
		if (k==0 || words[j]==words[k])
		{
			j ++;k ++;
			next[j] = k;
		}
		else k = next[k];
	}
}

char tree[4000010];

void brush(long l,long r,long i,long ll,long rr)
{
	long mid = (l+r)>>1;
	if (ll<=l && rr>=r)
	{
		tree[i] = 1;
		return;
	}
	if (rr < mid+1)
	{
		brush(l,mid,i<<1,ll,rr);
	}
	if (ll > mid)
	{
		brush(mid+1,r,(i<<1)+1,ll,rr);
	}
	if (ll<=mid && rr>mid)
	{
		brush(l,mid,i<<1,ll,rr);
		brush(mid+1,r,(i<<1)+1,ll,rr);
	}
	if (tree[i<<1] == tree[(i<<1)+1])
		tree[i] = tree[i<<1];
	else
		tree[i] = 2;
}

void output(long l,long r,long i,char *a)
{
	if (l == r)
	{
		if (isalpha(a[l]) && tree[i]==1)
			printf("*");
		else
			printf("%c",a[l]);
		return;
	}
	if (tree[i] < 2)
	{
		for (long j=l;j<r+1;j++)
		{
			if (isalpha(a[j]) && tree[i]==1)
				printf("*");
			else
				printf("%c",a[j]);
		}
		return;
	}
	long mid = (l+r)>>1;
	output(l,mid,i<<1,a);
	output(mid+1,r,(i<<1)+1,a);
}

void kmp(char *a,long lena,char *b,long lenb,long *next)
{
	long i=1;
	long j=1;
	while (i<lena+1)
	{
		if (j==0 || a[i]==b[j])
		{
			j ++;i ++;
		}
		else if (!isalpha(a[i]) && j<lenb+1)
		{
			i ++;
		}
		else j = next[j];

		if (j == lenb+1)
		{
			long q = i-1;
			for (long p=1;p<lenb+1;p++)
			{
				while (!isalpha(a[q])) q--;
				q --;
			}
			q ++;

			if (!isalpha(a[q-1]) && !isalpha(a[i]))
				brush(1,lena,1,q,i-1);
		}
	}
}

char source[10010][310];
long next[10010][310];
char words[1000010];
long lenth[1000010];

int strcmpr(const void* a,const void* b)
{
	return strcmp((char*)a,(char*)b);
}

long binary(long l,long r,char a)
{
	long rs = r+1;
	while (l <= r)
	{
		long mid = (l+r)>>1;
		if (source[mid][1]>=a)
		{
			if (rs > mid)
				rs = mid;
			r = mid-1;
		}
		else
			l = mid+1;
	}
	return rs;
}

int main()
{
	freopen("words.in","r",stdin);
	freopen("words.out","w",stdout);
	
	long k;
	scanf("%ld",&k);

	for (long i=1;i<k+1;i++)
	{
		scanf("%s",source[i]+1);
	}
	
	qsort(source+1,k,sizeof(source[0])/sizeof(char),strcmpr);
	for (long i=1;i<k+1;i++)
	{
		long j = 0;
		while (source[i][++j])
			if (isalpha(source[i][j]))
				source[i][++lenth[i]] = source[i][j];

		next_init(source[i],lenth[i],next[i]);
	}

	gets(words+1);
	gets(words+1);

	long lle = strlen(words+1);
	for (long i=binary(1,k,words[1]);source[i][1]==words[1] && i<k+1;i++)
		kmp(words,lle,source[i],lenth[i],next[i]);
	output(1,lle,1,words);

	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值