首页 > 其他分享 >刷题 字典树 LCP(最长公共前缀)

刷题 字典树 LCP(最长公共前缀)

时间:2023-12-05 21:57:27浏览次数:29  
标签:ch 前缀 LCP int ans 字符串 刷题 字典

2023.12.5 cf 1902E

字典树的功能

根据字典树的概念,我们可以发现:字典树的本质是把很多字符串拆成单个字符的形式,以树的方式存储起来。所以我们说字典树维护的是”字典“。那么根据这个最基本的性质,我们可以由此延伸出字典树的很多妙用。简单总结起来大体如下:

1、维护字符串集合(即字典)。

2、向字符串集合中插入字符串(即建树)。

3、查询字符串集合中是否有某个字符串(即查询)。

4、统计字符串在集合中出现的个数(即统计)。

5、将字符串集合按字典序排序(即字典序排序)。

6、求集合内两个字符串的LCP(Longest Common Prefix,最长公共前缀)(即求最长公共前缀)。

 

本题思路

先算出所有组合不折叠的长度ans,之后再慢慢减去折叠长度

先插入建树,再查询字符串的反转(reverse),将折叠长度转化为LCP,减去LCP乘以2即可

 

踩过的坑

如果结点下标起始你设为0,那要注意一些值为0的东西对题目的影响(最好设成1算了),比如本题中的query,因为可能会遇到ch[i][j]为0,这样会导致p回到0,所以一定要break,但如果你的根下标为1就没有这个必要,因为0此时和任何字符都没有连接,ch[0][k]永远都是0,没有影响。

 

代码

 

#include<iostream>//以根下标为0举例,最好用1还是 
#include<string>
#include<algorithm>
using namespace std;
#define ll long long
const int N=1000005;
int ch[N][30],cnt[N];
string s[N];
int idx;
ll ans=0;
void insert(string s)
{
	int p=0;
	for(auto c:s)
	{
		int j=c-'a';
		if(!ch[p][j])ch[p][j]=++idx;
		p=ch[p][j];
		cnt[p]++;
	}
}
void query(string s)
{
	int p=0;
	for(auto c:s)
	{
		int j=c-'a';
		if(!ch[p][j])break;
		p=ch[p][j];
		ans-=2*cnt[p];
	}
}
int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>s[i];
		ans+=s[i].length();
		insert(s[i]);
	}
	ans*=n*2;
	for(int i=1;i<=n;i++)
	{
		reverse(s[i].begin(),s[i].end());
		query(s[i]);
	}
	cout<<ans<<endl;
	return 0;
}

标签:ch,前缀,LCP,int,ans,字符串,刷题,字典
From: https://www.cnblogs.com/modemingzi-csy/p/17878363.html

相关文章

  • 刷题复习(二)数组-双指针
    刷题复习(二)数组-双指针https://labuladong.gitee.io/algo/di-ling-zh-bfe1b/shuang-zhi-fa4bd/1、删除有序数组中的重复项慢指针用于统计不重复项,快指针用于不停前进对比是否有新的不重复项,有的话进行替换classSolution{publicintremoveDuplicates(int[]nums){......
  • 2023年广东工业大学腾讯杯新生程序设计竞赛不知道叫什么名字(前缀和)
    需要的是男生女生数量相同,做个转化,女生变成-1,然后求一遍前缀和,我们希望找到最长的满足\(sum(l,r)=0\)的区间也就是\(sum(r)-s(l-1)=0\)考虑枚举右端点,找到最左端和它相等的sum就是对于当前右端点的最长的。最开始想了个二分答案的假做法,011100,这里答案是6,长度为4不满足......
  • 【刷题笔记】124. Binary Tree Maximum Path Sum
    题目Givena non-empty binarytree,findthemaximumpathsum.Forthisproblem,apathisdefinedasanysequenceofnodesfromsomestartingnodetoanynodeinthetreealongtheparent-childconnections.Thepathmustcontain atleastonenode anddoes......
  • Leetcode刷题day5-哈希表.异位词.交集.快乐数.两数和
    242.有效的字母异位词242.有效的字母异位词-力扣(LeetCode)给定两个字符串 _s_ 和 _t_ ,编写一个函数来判断 _t_ 是否是 _s_ 的字母异位词。注意:若 _s_ 和 _t_ 中每个字符出现的次数都相同,则称 _s_ 和 _t_ 互为字母异位词。示例 1:输入:s="anagram",......
  • 前缀和/差分——acwing算法基础课笔记
    个人笔记,欢迎补充,指正。一维前缀和对于数组:a[1],a[2],a[3]...a[n];其前缀和数组为s[i]=a[1]+a[2]+...+a[i];下标必须从1开始求前缀和1for(inti=1;i<n;++i)2s[i]=s[i-1]+a[i];s[0]需要定义为0作用求原数组里一段数(l,r)的和......
  • Leetcode刷题day4-链表.交换.删除.相交.环
    24.两两交换链表中的节点24.两两交换链表中的节点-力扣(LeetCode)给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(只能进行节点交换)。示例1:输入:head=[1,2,3,4]输出:[2,1,4,3]示例2:输入:head=[]输出:[......
  • 刷题 后缀和 贪心
    2023.12.2cf1903C 解题思路(听说是个常见的形式)  a:第一个部分b:第二个部分c:第三个部分 本题1*a+2*b+3*c......这种形式可以拆成 a+b+c+...... 加上 b+c+...... 加上 c+...... 由以上看出可以构造后缀和 再证明贪心: 当a*n+b*(n+1)>(a+b)*n......
  • 一个算法笨蛋的11月leetCode刷题日记
    时间情况2021年10月29日时隔一年,第三次重做反转链表,又没做出来,太废了。2021年11月1日时隔两天,第四次重做反转链表,轻松写出【21】合并两个有序链表(思路:想象两个有序链表,需要新建两个next指向头节点的空node,一个用于最后返回.next,一个用于接收最小的node)【206】反转链表(思路:......
  • 【牛客刷题】
    scanf读入16进制数写出一个程序,接受一个十六进制的数,输出该数值的十进制表示。 数据范围:保证结果在1≤n≤2^31−1 我的解法:voidHexToDec(void){uint32_tresult=0;scanf("%x",&result);printf("%d",result);}scanf("%x",&n);就可以接收16进制数据。......
  • 刷题建议
    刷题这件事情本身也是需要「方法」的。我们针对算法面试准备的算法题,不是智力题,我们觉得刷题有困难,有很大一部分是心理上的因素。其实这一类算法问题非常像我们初高中的数学问题,知识点很多,都有相对固定的思考方向和常考的知识点,答案和思路也是相对固定的。刷题这件事情我觉得一......