字符串学习笔记

如题。

链接:https://gxyzoj.com/d/hzoj/training/64ae62d5016fac9fb4da7089

P366. 「一本通 2.3 例 1」Phone List

date : 2023.12.11

字典树 \(trie\) 的模板题。这是我上洛谷搜了之后才知道的。。

早上试过哈希、数字结果都 T 了,跑大数据要9秒,下午地理课才现学字典树去写的。

字典树很好理解,也很好写,就是利用字符串 ASCLL 码去找前缀,然后往下一直建节点之类的。

参考博客:https://www.luogu.com.cn/blog/juruohyfhaha/trie-xue-xi-zong-jie

参考代码:

#include<bits/stdc++.h>
using namespace std;
struct node{
	int son[11],sum;
	bool f;
}trie[100110];
int n,t,num;
string s[100010];
void ins(string c)
{
	int len=c.size(),u=0;
	for(int i=0;i<len;i++)
	{
		int v=c[i]-'0';
		if(!trie[u].son[v])
		trie[u].son[v]=++num;
		trie[u].sum++;
		u=trie[u].son[v];
	}
	trie[u].f=1;
}
int find(string c)
{
	int len=c.size(),u=0;
	for(int i=0;i<len;i++)
	{
		int v=c[i]-'0';
		if(!trie[u].son[v]) return 0;
		u=trie[u].son[v];
	}
	if(trie[u].sum==0) return 0;
	return 1;
}
int main()
{
	cin>>t;
	while(t--)
	{
		num=0;
		memset(trie,0,sizeof(trie));
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			cin>>s[i];
			ins(s[i]);
		} 
		for(int i=1;i<=n;i++)
		{
			if(find(s[i]))
			{
				printf("NO\n");
				goto end;
			}
		}
		printf("YES\n");
		end:;
	}
}

字典树只有 \(insert\) 操作和 \(find\) 操作,比线段树好些多了。

P367. 「一本通 2.3 例 2」The XOR Largest Pair

同样的字典树,不同的存法和读法。

这个数据结构叫做 \(0/1 \ Trie\) 。就是把一个数拆成二进制,然后再和字符串一样存到 \(Trie\) 里头。

代码和普通 \(Trie\) 仅有一点差别,就是一个 \(Trie\) 的节点只有两个 \(son\) ,分别代表 \(0\)\(1\)

代码:

#include<bits/stdc++.h>
using namespace std;
struct node{
	int son[5],sum;
	bool f;
}trie[10000005];
int cnt;
int las[10000005];
void ins(int a)
{
	int u=0;
	for(int i=31;i>=0;i--)
	{
		int ch=(a>>i)&1;
		if(!trie[u].son[ch])
		trie[u].son[ch]=++cnt;
		trie[u].sum++;
		u=trie[u].son[ch];
	}
	las[u]=a;
}
int find(int a)
{
	int u=0;
	for(int i=31;i>=0;i--)
	{
		int v=(a>>i)&1;
		if(trie[u].son[v^1])
		{
			u=trie[u].son[v^1];
		}
		else
		{
			u=trie[u].son[v];
		}
	//	u=trie[u].son[v];
	}
	return a^las[u];
}
int num[100010];
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&num[i]);
		ins(num[i]);
	}
	int ans=-114514191;
	for(int i=1;i<=n;i++)
	{
		ans=max(ans,find(num[i]));
	}
	cout<<ans;
}

P368. The XOR-longest Path

依然是 \(0/1 \ Trie\) 。只不过在前面要先用 \(bfs\) 预处理一下节点到根的异或,然后和上题一样。

P370. 「一本通 2.3 例 3」Nikitosh 和异或

卡常的**题目。真的无语。依然是 \(0/1 \ Trie\) ,两次分别从前往后和从后往前去处理异或前缀和和后缀和,然后再存到 \(Trie\) 里头。




剩下的题目等到学完基础数论以后再搞吧,先去鸽数论了。

posted @ 2024-02-20 19:48  ccjjxx  阅读(14)  评论(0编辑  收藏  举报