【HT-086-Div.2】错乱的集合

news/2025/11/14 20:18:24/文章来源:https://www.cnblogs.com/qwqSW/p/19223217

比赛现场

更阅读体验的阅读体验

是个好题。但是我赛时怎么什么都不会。


首先简化一下题面:\(s\)\(t\) 被认为是相同的,当且仅当 \(s=t\)\(|t|=|s|-1\)\(t\)\(s\) 的后缀(或者反过来 \(s\) 是后缀)。

(以下都假设 \(s\) 是较长的那个)

那这样的话,\(s\) 就是 \(t\) 前面多一个字母。\(s\) 如果在集合里的话,\(t\) 就不能在集合里。反之亦然。

我们又考虑到,\(s\) 只会有一个对应的后缀 \(t\),但是 \(t\) 前面可以加任意字母构成任意的 \(s'\),也就是 \(t\) 会和多个较长的 \(s'\) 构成不合法关系。换句话说,这是个一对多的关系,约等于一个森林。

那这不就是《没有上司的舞会》吗?对的对的,如果我们把树建出来的话就能直接套用那个题的做法了。

那咋建树呢?或者说对于一个字符串 \(s\) 的话,怎么让它所有的前缀和它们不合法的那个后缀建上边呢?或者我们怎么找不合法后缀呢?

关键词:前缀。考虑用 Trie 树。我们把所有的串串扔进一个 Trie 树里。

原题解这里讲的不太清楚。我的理解是,对于第 \(i\) 个串 \(s_i\),我们从小到大枚举 \(j\) 表示当前这个前缀截止到 \(j\) 这个位置。

(由于我的坐标从 1 开始,所以我的 \(j \in [1,len]\)。)

我们对于每个 \(j\) 要看看是否有一个不合法后缀 \(s_{2,3,\cdots,j}\) 存在于 Trie 树上,有的话说明存在这样的前缀不能和当前前缀一个集合,我们就将当前前缀在树上的编号与这个前缀在树上的编号建边。

显然 \(j=1\) 时是没有这样的后缀的。当 \(j \in [2,len]\) 时,每当 \(j \to j+1\),那么当前要找的不合法后缀也会加一个对应字符。

比如我们考虑 abb 这个前缀的时候,它要找的不合法后缀是 bb。当我们考虑完这个位置,考虑 abba 这个前缀的时候,要找的不合法后缀也会多一个字母 a 变成 bba

这对应到 Trie 树上是什么?假设我们已经找完了 \(j\) 位置的不合法后缀,我们找 \(j+1\) 的时候,让 \(now \to tr_{now,s[i][j+1]}\),在树上往下跳即可。

如果找到了就像前面说的一样建边,如果找不到了就说明没有这样的后缀了,后面的前缀也不会再有了,直接跳出循环。

这样我们把树建好以后,跑一遍树上 dp 即可。

代码:

T2代码
#include<bits/stdc++.h>
#define int long long
using namespace std;inline int read(){int x=0,f=1;char c=getchar();while(c<48){if(c=='-') f=-1;c=getchar();}while(c>47) x=(x<<1)+(x<<3)+(c^48),c=getchar();return x*f;
}const int N=1e6+6;
int T,n,tr[N][30],awa,dp[N][2],h[N],fa[N],tot;
//tr:Trie 树
//awa:当前Trie树节点开到哪了 
//dp:树上dp数组
//fa[i]:Trie树上编号为 i 的点要向哪个点连边 
vector<int> pos[N];
//pos[i][j]:第 i 个串长度为 j 的前缀对应 Trie 树上的哪个点 
string s[N];
struct sw{int u,v,nxt;
}e[N];inline void INIT(){for(int i=0;i<=awa;i++){dp[i][0]=dp[i][1]=0;fa[i]=0;h[i]=0;for(int j=1;j<=26;j++){tr[i][j]=0;}}awa=0;for(int i=1;i<=tot;i++){e[i]={0,0,0};}tot=0;
}inline void INITT(){for(int i=1;i<=n;i++){pos[i].clear();s[i]=' ';}
}inline void add(int u,int v){e[++tot]={u,v,h[u]};h[u]=tot;
}inline void dfs(int u){//树上dp,不会的可看P1352,不过这里每个点的点权是1 dp[u][1]=1;for(int i=h[u];i;i=e[i].nxt){int v=e[i].v;dfs(v);//考虑选u点的情况,此时子节点不能选 dp[u][1]+=dp[v][0];//考虑不选u点的情况,此时子节点任意 dp[u][0]+=max(dp[v][0],dp[v][1]);}
}inline void ins(int id){//Trie树里的插入操作 int len=s[id].size()-1,now=0;pos[id].push_back(0);for(int i=1;i<=len;i++){int fu=s[id][i]-'a'+1;if(!tr[now][fu]){tr[now][fu]=++awa;}   now=tr[now][fu];pos[id].push_back(now);}
}signed main(){freopen("b.in","r",stdin);freopen("b.out","w",stdout);T=read();while(T--){//多测记得初始化 INIT();n=read();INITT();for(int i=1;i<=n;i++){cin>>s[i];s[i]=' '+s[i];ins(i);}//处理每个点往哪里连边 for(int i=1;i<=n;i++){int now=0,len=s[i].size()-1;for(int j=2;j<=len;j++){int fu=s[i][j]-'a'+1;if(!tr[now][fu]){//没有找到不合法后缀,说明后面的点也找不到了 now=-1;break;} now=tr[now][fu];//否则当前前缀记录往now上连边 fa[pos[i][j]]=now;}}//我们发现,对于没有限制的点,默认会往 0 号点连边,这样不仅是正确的(它们在dp里一定会被选),还不用再单独处理这种情况了 for(int i=1;i<=awa;i++){add(fa[i],i);}dfs(0);//由于 0 号点是虚拟的,所以选了没有意义,且有可能搞掉正确答案的选法 int ans=dp[0][0];printf("%lld\n",ans);}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/965682.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

uiautomator2元素查看器WEditor的安装和启动

WEditor 一、WEditor简介 在执行APP UI自动化测试时,需要使用到元素定位,通常我们会直接使用appium Desktop的Inspector。介绍另一款UI元素定位的工具--WEditor。WEditor能够提供辅助编写脚本,定位元素,调试代码等…

深入解析:【从0开始学习Java | 第22篇】反射

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

【题解】LOJ6300. 「CodePlus 2018 3 月赛」博弈论与概率统计

首先转化成总和除以方案数的形式。 先想想一条路径的答案是什么,显然是 \(n - m + cnt\),其中 \(cnt\) 为没用的输局。 这种东西显然非常能够转化成网格计数。起点为 \((0, 0)\) 终点为 \((n, m)\) 赢一局向右一步,…

感情粉末沿着试管边缘 在祝福中逐渐分解 加热认知离子重新排列 于底部悲伤沉淀

test39 降水 令 \(a_i\gets \frac{a_i}{2}\),先计算出 \(\sum a_i=\frac{\sum p_i}{2}\),然后因为限定了 \(n\) 的奇偶性容易减出 \(a_n\),然后容易依次求出 \(a_1,\dots,a_{n-1}\)。 #pragma GCC optimize(1,2,3,&…

C#循序渐进 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2025.11.14 - A

今天形势与政策,学习了一些尝试,加油

从RvmTranslator到PlantAssistant

将RvmTranslator中的剖切功能和根据名称查找功能迁移到PlantAssistant中来。引言 RvmTranslator主要是处理AVEVA的RVM文件,现在的PlantAssistant不仅可以解析RVM文件,还可以解析SP3D的VUE文件,所以RvmTranslator不再…

MI50 在ubuntu 下 风扇控制实现

关于MI50的风扇控制问题,之前很长一段时间都是win上使用,主要是win上解决了MI50风扇控制问题,使用‌Fan-Control软件+HWInfo解决。在windows下有很多处理风扇控制的成熟方案,主要是win下驱动问题比较好解决,部分l…

PortSwigger靶场之 CSRF where token is not tied to user session通关秘籍 - 实践

PortSwigger靶场之 CSRF where token is not tied to user session通关秘籍 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; fon…

nvm不能下载安装低版本node解决办法

nvm不能下载安装低版本node解决办法 场景 以前下载还是可以的,比如10/12/14之类的 但是近期发现:16以下版本无法下载,下载报错 解决 访问node官网 选择对应系统,对应版本的压缩包,下载 下载后解压到桌面, 剪贴到…

完整教程:【实时Linux实战系列】实时 Linux 在边缘计算网关中的应用

完整教程:【实时Linux实战系列】实时 Linux 在边缘计算网关中的应用2025-11-14 19:56 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto …

flask: 抛出异常

一,代码: 异常 处理: #-------------------------------------异常处理----------------------------- @app.errorhandler(Exception) def handle_exception(error):stack = traceback.format_exc()app.logger.erro…

20251114——读后感5

自动化能提高效率,如自动化测试。写接口时,用JUnit写单元测试,一键运行就能发现逻辑错误,比手动测试高效且覆盖全面,像测试用户注册功能,自动测试能快速验证各种输入情况。

雪地奔驰全等级提升所需经验一览

雪地奔驰升级所需经验一览,游戏目前版本最高等级为30级,下面就为大家分享全等级所需经验,供各位玩家们参考。

2025皮肤亚健康管理品牌最新专业推荐:科技赋能健康美新生态

随着消费者对皮肤健康管理需求的升级,专业皮肤亚健康管理服务市场迎来爆发式增长。本榜单基于技术创新力、产品体系、服务效能三大维度,结合行业权威数据与用户反馈,深度解析2025年五大皮肤亚健康管理品牌综合实力,…

【HT-086-Div.2】嗡嗡蜜蜂

【HT-086-Div.2】嗡嗡蜜蜂 题解比赛传送门 更阅读体验的阅读体验 当时怎么就没想出来这个题呢,明明跟正解思路就差了一个左端点排序(我当时以为右端点排序呢)我们枚举这 \(n\) 个区间,考虑当前某个区间 \(i\) 区间…

第四十一篇

今天是11月14号,上了形策

深入解析:Vue3 路由配置和使用与讲解(超级详细)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

好题集 (0) - 目录

之前的做题记录咕太多了,而且本身意义也不大。于是效仿 xak 同学搞了这个,用于记录少数做完之后觉得非常强势的题。 0x01 - LG P3978 [TJOI2015] 概率论:卡特兰数,排列组合 0x02 - LG p4550 收集邮票:期望 DP,大…