字符串学习笔记

如题。

链接: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 ,分别代表 01

代码:

#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 里头。

P8819 [CSP-S 2022] 星战

一年了,终于有机会重新做这道题了。

看似和字符串没关系,实则却是没啥关系。

考虑能进行反攻的条件。首先,能进行无限次反攻,换成人话就是图里有环。但是考虑到这个是有向图,那就每个点的入度不为零。若要实现连续穿梭,则是要求整张图是一个完整的环。那就是每个点的入度都为 1

如何判定?显然,对于每次询问,维护的入度都是 O(1) 修改的,但是查询所有的入度显然是 O(n) 的。总复杂度 O(nq)

究其原因,是因为每个点的标识不清晰,导致必须遍历全部的点才能判断每个点的出度是否都是 1

然后,考虑如何 O(1) 地判定一个状态是否是合法的,可以参考 noip模拟1的 T2,对每个点进行特异化处理,即给它一个随机化权值 vali,合法状态一定满足当前入度和严格等于 vali

然后就好做了,代码很短。

posted @   ccjjxx  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示