【ybt高效进阶2-4-4】【luogu P3879】阅读理解

阅读理解

题目链接:ybt高效进阶2-4-4 / luogu P3879

题目大意

有一些句子,然后有一些问的单词。
对于每个问的单词,我们要求它在哪几个句子出现过。

思路

我们看到匹配单词,就会想到 Trie 树。

那用句子里的单词建 Trie 树不太好,因为单词太多,那我们可以用要用的单词建 Trie 树。
那我们建 Trie 树之后,就像模板一样搞就好了。

但是这题很狗,一个句子中可能同时出现一个你要的单词多次,或者有几个你要的单词的一样的。

那我们分别来解决这两个问题。
第一个问题,我们判断一下在这个句子中有没有出现过你现在发现的这个单词,没有才加入。
第二个问题,我们可以在建 Trie 树的时候如果原来有在这个点建过(或者说就是原来出现了这个字符串),那我们可以把它也记录下来(我是用邻接表的方式来记录)。
然后你找到一个数的时候,你就顺着邻接表,把每个数都标记一次。

当然你记录每个单词在哪里出现可以用 vector 来存。

代码

#include<cstdio>
#include<vector>
#include<cstring>

using namespace std;

struct Trie {
	int son[28], word;
}tree[200001];
int n, m, KK, size[10001], l, r, now, tmpn;
int have_next[10001];
char c[1001][5001], tmp[10001];
bool have[10001];
vector <int> a[10001];

void build(int word) {
	now = 0;
	for (int i = 0; i < tmpn; i++) {
		if (!tree[now].son[tmp[i] - 'a']) tree[now].son[tmp[i] - 'a'] = ++KK;
		now = tree[now].son[tmp[i] - 'a'];
	}
	if (!tree[now].word) tree[now].word = word;//因为规定的单词会有重复,那我们可以弄个类似邻接表的东西来标记完所有相同的位置
		else {
			have_next[word] = tree[now].word;
			tree[now].word = word;
		}
}

void ask(int op, int l, int r) {
	now = 0;
	for (int i = l; i <= r; i++)
		if (!tree[now].son[c[op][i] - 'a']) return ;
			else {
				now = tree[now].son[c[op][i] - 'a'];
			}
	if (tree[now].word && !have[tree[now].word]) {//按着邻接表一个一个标记
		have[tree[now].word] = 1;
		a[tree[now].word].push_back(op);
		int noww = tree[now].word;
		while (have_next[noww]) {
			noww = have_next[noww];
			a[noww].push_back(op);
		}
	}
}

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &size[i]);
		gets(c[i]);
	}
	
	scanf("%d", &m);
	for (int i = 1; i <= m; i++) {//先把每一个要看的单词建Trie树
		scanf("%s", &tmp);
		tmpn = strlen(tmp);
		build(i);
	}
	
	for (int i = 1; i <= n; i++) {
		memset(have, 0, sizeof(have));
		size[i] = strlen(c[i]);
		size[i]--;
		l = 1;
		r = 1;
		while (r <= size[i] - 1) {
			while (c[i][r] != ' ' && r <= size[i] - 1) r++;
			
			ask(i, l, r - 1);//看这个句子中的这个单词是否是要的单词
			
			l = r + 1;
			r = l;
		}
	}
	
	for (int i = 1; i <= m; i++) {
		KK = a[i].size();
		for (int j = 0; j < KK; j++) {
			printf("%d ", a[i][j]);
		}
		
		printf("\n");
	}
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值