字符串学习笔记
如题。
链接: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\) 里头。
剩下的题目等到学完基础数论以后再搞吧,先去鸽数论了。