首页 > 其他分享 >Trie字典树和AC自动机 (题目&答案)

Trie字典树和AC自动机 (题目&答案)

时间:2024-06-05 12:29:56浏览次数:24  
标签:AC ch idx Trie ++ cnt int 自动机 scanf

A. 三年二班的投票

题目描述

三年级二班已经完成了竞选班长的投票,已知一共有 n 张投票,每张投票上写了一位同学的名字。

投票统计结束后,张老师随意问一个同学的名字,请编程快速检索出,该同学共有几票。

输入

第一行读入一个整数 n ,代表产生了 n 张投票。( n≤10^{5}

接下来 n 行,每行有一个字符串 s ,代表该张投票上写的同学的姓名(姓名由不含空格的小写英文字母组成,n 个姓名的总长度 ≤10^{6} )。

接下来一行读入一个整数 m( m≤10^{5} ),代表王老师提问的同学的姓名数量。

接下来 m 行,每行有一个字符串 ttt ,代表每次询问的姓名;(姓名由不含空格的小写英文字母组成,m 个姓名的总长度 ≤10^{6} )。

输出

输出 m 行,第 i 行输出第 i 次询问的姓名,在投票中出现的总次数。

样例

输入:

5
lihua
zhaoxiang
wangfang
lihua
zhangxiang
3
lihua
wangfang
sunming

输出:

2
1
0

代码如下:

#include <bits/stdc++.h>
using namespace std;

const int N = 1e6 + 10;
//下标为0的行,表示根,也表示空节点 
int ch[N][26];//字典树
//cnt:以第i个字母结尾的单词有多少个 
int cnt[N],idx; 
char s[N];//每次读入的名字
int n,m;

//建字典树
void insert(char s[]){
	int p = 0;//从下标为0的行开始
	for(int i = 0;s[i];i++){
		int u = s[i] - 'a';//转换为0~25
		//如果p节点不存在u这个子结点,则创建子结点 
		if(!ch[p][u]) ch[p][u] = ++idx;
		p = ch[p][u];
	} 
	cnt[p]++;//结束,以第p个字母结尾的字符串数量+1 
} 

//查询:返回字符串出现的次数
int query(char s[]){
	int p = 0;
	for(int i = 0;s[i];i++){
		int u = s[i] - 'a';
		if(!ch[p][u]) return 0;//没有出现
		p = ch[p][u]; 
	}
	
	return cnt[p];
}

int main(){
	scanf("%d",&n);
	while(n--){
		scanf("%s",s);
		insert(s);
	}
	scanf("%d",&m);
	while(m--){
		scanf("%s",s);
		printf("%d\n",query(s));
	}
	return 0;
}

B. 数字串前缀匹配

题目描述

给定 n 个长度不超过 10 的数字串,问其中是否存在两个数字串 S,T,使得 S 是 T 的前缀。

本题读入多组数据,请对每组数据进行计算并输出结果。(数据组数≤40,n≤10^{4}

输入

第一行一个整数 T,表示数据组数。

对于每组数据,第一行一个数 n,接下来 n 行输入 n 个数字串。

输出

对于每组数据,若存在两个数字串 S,T,使得 S 是 T 的前缀,则输出 NO ,否则输出 YES

样例:

输入:

2
3
911
97625999
91125426
5
113
12340
123440
12345
98346

输出:

NO
YES

代码如下:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int ch[N][10],cnt[N],idx = 0;
char s[20];
int T,n;
bool insert(char s[]){
	bool f1 = false,f2 = false;
	int p = 0;
	for(int i = 0;s[i];i++){
		int x = s[i] - '0';
		if(!ch[p][x])ch[p][x] = ++idx,f1 = true;
		p = ch[p][x];
		if(cnt[p] != 0)f2 = true;
	}
	cnt[p]++;
	return (f1==false) || f2;
}
int main(){
	scanf("%d",&T);
	while(T--){
		memset(ch,0,sizeof(ch));
		memset(cnt,0,sizeof(cnt));
		idx = 0;
		scanf("%d",&n);
		bool f = false;
		while(n--){
			scanf("%s",s);
			if(insert(s))f = true;
		}
		if(f)cout<<"NO"<<endl;
		else cout<<"YES"<<endl;
	}
	return 0;
} 

C. 关键词搜索

题目描述

给定 n 个长度不超过 50 的由小写英文字母组成的单词准备查询,以及一篇长为 m 的文章,问:文中出现了多少个待查询的单词。多组数据。

输入

第一行一个整数 T,表示数据组数;
对于每组数据,第一行一个整数 n,接下去 n 行表示 n 个单词,最后一行输入一个字符串(不含空格),表示文章。(对于全部数据,1≤n≤10^{4},1≤m≤10^{6} 。)

输出

对于每组数据,输出一个数,表示文中出现了多少个待查询的单词(注意:同一个单词在文章中出现多次,也只算一次)。

样例

输入:

1
5
she
he
say
shr
her
yasherhs

输出:

3

代码如下:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10,M = 1e6 + 10,L = 55;
int ch[N*L][26],cnt[N*L],idx = 0;
int ne[N*L];
int q[N*L];
char w[L],s[M];
int T,n;
void init(){
	memset(ch,0,sizeof(ch));
	memset(cnt,0,sizeof(cnt));
	idx = 0;
	memset(ne,0,sizeof(ne));
}
void insert(char w[]){
	int p = 0;
	for(int i=0;w[i];i++){
		int x = w[i] - 'a';
		if(!ch[p][x])ch[p][x] = ++idx;
		p = ch[p][x];
	}
	cnt[p]++;
}
void bfs(){
	int h = 1,t = 0;
	for(int i = 0;i < 26;i++){
		if(ch[0][i])q[++t] = ch[0][i];
	}
	while(h <= t){
		int f = q[h];
		for(int i = 0;i < 26;i++){
			if(ch[f][i]){
				int c = ch[f][i];
				int j = ne[f];
				while(j && !ch[j][i])j = ne[j];
				if(ch[j][i])j = ch[j][i];
				ne[c] = j;
				q[++t] = c;
			}
		}
		h++;
	}
}
int main(){
	scanf("%d",&T);
	while(T--){
		init();
		scanf("%d",&n);
		while(n--){
			scanf("%s",w);
			insert(w);
			
		}
		bfs();
		scanf("%s",s);
		int res = 0;
		for(int i = 0,j = 0;s[i];i++){
			int x = s[i] - 'a';
			while(j && !ch[j][x])j = ne[j];
			if(ch[j][x])j = ch[j][x];
			int p = j;
			while(p != 0){
				res += cnt[p];
				cnt[p] = 0;
				p = ne[p];
			}
		
		}
		printf("%d\n",res);
	}
	return 0;
} 

好了,今天的题目&答案到此为止qwq

标签:AC,ch,idx,Trie,++,cnt,int,自动机,scanf
From: https://blog.csdn.net/jt6666678/article/details/139449160

相关文章

  • Oracle 表内数据量少,但是查询速度很慢
    优化方向1.使用合适的索引:确保查询中涉及的字段有适当的索引。索引可以帮助数据库引擎快速定位和检索数据,提高查询效率。2.避免使用通配符查询:尽量避免在查询条件中使用通配符'%',因为这样的查询会导致全表扫描,影响性能。3.避免使用函数:在查询条件中避免使用函数,尽量在字段上......
  • 阿里云OSS对象存储怎么开通?怎么设置APIAccessKey申请教程?
    阿里云OSS对象存储怎么开通?怎么设置APIAccessKey申请教程?阿里云的产品线众多,后台功能复杂,聚搜云有时候找一些产品或者功能的时候,也是找的云里雾里。比如聚搜云这次需要用到阿里云OSS,我们都知道国内的带宽是小水管,如果用来常规的建站用途,其实也没什么大问题,但是如果静态资源......
  • C# Parallel foreach Parallel Source array was not long enough. Check srcIndex an
    //Indexwasoutsidetheboundsofthearray.//Sourcearraywasnotlongenough.ChecksrcIndexandlength,andthearray'slowerbounds//usingSystem;usingSystem.Collections.Concurrent;usingSystem.Collections.Generic;usingSystem.Linq;usingSy......
  • Python数据分析案例45——基于融合模型(Stack)的电商用户购买行为预测
    案例背景最近618快到了,上电商购买的人很多,正好我手上还有这个用户购买行为的数据,就做了一个机器学习模型流程,然后也使用的都是常见的机器学习模型,但是加了一点创新吧,使用了stacking融合模型。简单来说就是使用了很多机器学习模型一起融合,这样的好处在于会降低方差,使预测结果更......
  • 使用Apache POI操作Excel
    案例一:(创建工作表)在使用ApachePOI操作Excel时,如果要处理大量的数据(例如十万级别的行),则需要特别注意性能优化。以下是一些优化建议和详细说明:使用SXSSFWorkbook:SXSSFWorkbook是XSSFWorkbook的流式版本,可以有效地节省内存,因为它会将数据写入磁盘而不是全部保存在内存中。这是......
  • faceswap软件安装教程
    下载软件访问faceswap网站,下载对应的软件版本,faceswap下载地址,下载完成,打开软件后看到的软件目录如下:安装faceswap软件安装miniconda软件(非必须),其它python虚拟环境亦可,miniconda安装教程自行检索,安装完成后创建虚拟环境condacreate-nenv_namepython=3.9.19安装软......
  • 分析webpack编译结果, 实现__webpack_require__函数
    分析webpack编译结果,实现__webpack_require__函数本篇文章我们通过手写来分析一下Webpack打包后的代码,并研究一下Webpack是如何将多个模块合并在一起的首先控制台输入npminit-y初始化一个项目,再输入npmiwebpackwebpack-cli-D安装Webpack在src目录想创建入......
  • Vue3-shallowRef与shallowReactive
    shallowRef作用:创建一个响应式数据,但只对顶层属性进行响应式处理。用法:letmyVar=shallowRef(initialValue);特点:只跟踪引用值的变化,不关心值内部的属性变化。shallowReactive作用:创建一个浅层响应式对象,只会使对象的最顶层属性变成响应式的,对象内部的嵌套属......
  • acwing329 围栏障碍训练场 题解
    考试压轴题,意识到这题是线段树优化\(dp\)时追悔莫及。为了简化题目,我将从起点到原点变成了从原点到起点(这样就可以省去两个数组的空间)。想到设\(dp_{i,j}\)表示在第\(i\)层,奶牛们在\(j\)列时的最小移动范围,则转移方程为(设输入为\(l,r\)):\[\begin{cases}dp_{i,j}=dp_{......
  • ORACLE内存结构
    oracle内存结构主要有两部分组成,一个是系统全局区(SYStemGlobalArea,SGA),所有进程都可以访问该内存区域。另外一个叫进程全局区(ProcessGlobalArea,PGA),是一个进程专用的内存区域,其他进程不可以访问。1PGA介绍一个进程专用的内存区域,其他进程不可以访问。每个进程的PGA......