P1481魔族密码 题解(字典树)

魔族密码

题目背景

风之子刚走进他的考场,就……

花花:当当当当~~偶是魅力女皇——花花!!^^(华丽出场,礼炮,鲜花)

风之子:我呕……(杀死人的眼神)快说题目!否则……-_-###

题目描述

花花:……咦好冷我们现在要解决的是魔族的密码问题(自我陶醉:搞不好魔族里面还会有人用密码给我和菜虫写情书咧,哦活活,当然是给我的比较多拉*_*)。

魔族现在使用一种新型的密码系统。每一个密码都是一个给定的仅包含小写字母的英文单词表,每个单词至少包含 1 个字母,至多 75 个字母。如果在一个由一个词或多个词组成的表中,除了最后一个以外,每个单词都被其后的一个单词所包含,即前一个单词是后一个单词的前缀,则称词表为一个词链。例如下面单词组成了一个词链:

  • i
  • int
  • integer

但下面的单词不组成词链:

  • integer
  • intern

现在你要做的就是在一个给定的单词表中取出一些词,组成最长的词链,就是包含单词数最多的词链。将它的单词数统计出来,就得到密码了。

风之子:密码就是最长词链所包括的单词数阿……

输入格式

这些文件的格式是,第一行为单词表中的单词数 N1 ≤ N ≤ 2000),下面每一行有一个单词,按字典顺序排列,中间也没有重复的单词。

输出格式

输出共一行,一个整数,表示密码。

样例 #1

样例输入 #1

5
i
int
integer
intern
internet

样例输出 #1

4

tire基本板子

//插入
int son[N][M],idx;//N的取值一般是最大字符长度*字符个数,M的取值由字符串由什么构成决定
bool cnt[N];
//这里M取26
void insert(char str[]){
	int p=0,u;
	for(int i=0;str[i];i++){
		u=str[i]-'a';//将小写字母转换为数组方便存储
		if(!son[p][u]) son[p][u]=++idx;//如果字符串中的某一个字符在字典树中不存在,则创建该字符的节点
		p=son[p][u];//此时p就是当前str[i]中最后一个字符对应的字典树树的位置idx
	}
	cnt[p]=1;//在p位置上打个标记,说明该字符串出现过
}
//查询
//查询的代码类似,可以看上面的注释来理解
bool query(char str[]){
	int p=0,u;
	for(int i=0;str[i];i++){
		u=str[i]-'a';
		if(!son[p][u])return false;
		p=son[p][u];
	}
	return cnt[p];
}

AC Code

// Problem: 
//     P1481 魔族密码
//   
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1481
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<iostream>
#include<algorithm>
//#include<cstdio>
#include<cstring>
#define ll long long 
#define endl '\n'
#define rep(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=(a);i>(b);i--)
#define N 150100 //1e6+100 
 
using namespace std;
int son[N][26],idx;
char in[2010][80];
bool cnt[N];
void insert(char str[]){
	int p=0,u;
	for(int i=0;str[i];i++){
		u=str[i]-'a';
		if(!son[p][u])son[p][u]=++idx;
		p=son[p][u];
		//cnt[p]=cnt[p-1]+1;
	}
	cnt[p]=true;
}
bool query(char str[]){
	int p=0,u;
	for(int i=0;str[i];i++){
		u=str[i]-'a';
		if(!son[p][u])return false;
		p=son[p][u];
	}
	return cnt[p];
}
int main(){
	//ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int n;
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>in[i];
		insert(in[i]);
	}
	int MAX=0;
	char tmp[80],MAXstr[100];
	//这边采用暴力查找
	for(int i=0;i<n;i++){
		int res=0;
		for(int j=1;j<=strlen(in[i]);j++){
			memset(tmp,0,sizeof tmp);//要用memset是因为strncpy不会把后面的元素置为'\0',所以可能会产生运行中计算的错误。
			strncpy(tmp,in[i],j);
			if(query(tmp))res++;
		}
		MAX=max(MAX,res);
	}
	cout<<MAX<<endl;
	return 0; 
} 


  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值