题目链接:点击查看

题目大意:给出一个含有 nnn 个点的无向图,点权为一个字符串,每条边的边权为相邻两点的 LCSLCSLCS,本题的 LCSLCSLCS 定义为两个字符串的最长公共子串的长度

求出这个无向图中的一个生成树,使得边权之和最大

题目分析:多个字符串的子串问题,考虑广义后缀自动机

首先将 nnn 个字符串扔到广义后缀自动机里去,顺便记录一下每个字符串在哪些节点中出现,然后按照子串长度做最大生成树就可以了。

现在问题是,如果要将每个字符串所出现的节点都表示出来,会 TLE,原因是前缀的后缀太多了

我们需要换个思路,让每个 字符串 只在前缀的那个 子串节点 中表示出来,然后每次合并的时候,只需要考虑两种情况:

  1. 同节点的字符串
  2. 本节点子孙节点的字符串

贪心合并时需要一点技巧,这里参考了杨大佬的代码:

// Problem: LCS Spanning Tree
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/31454/I
// Memory Limit: 2097152 MB
// Time Limit: 10000 ms
//
// Powered by CP Editor (https://cpeditor.org)// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#define lowbit(x) (x&-x)
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{T f=1;x=0;char ch=getchar();while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=f;
}
template<typename T>
inline void write(T x)
{if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0');
}
const int inf=0x3f3f3f3f;
const int N=2e6+100;
int a[N<<1],f[N],root[N<<1];
char s[N];
vector<int>id[N<<1],node[N<<1];
int tot,last;
struct Node {int ch[26];int fa,len;
}st[N<<1];
inline int newnode() {tot++;for(int i=0;i<26;i++)st[tot].ch[i]=0;st[tot].fa=st[tot].len=0;return tot;
}
void add(int x) {int p=last;//if(st[p].ch[x]){int q=st[p].ch[x];if(st[q].len==st[p].len+1)last=q;else{int np=last=newnode();st[np].len=st[p].len+1;st[np].fa=st[q].fa;st[q].fa=np;for(int i=0;i<26;i++)st[np].ch[i]=st[q].ch[i];while(st[p].ch[x]==q)st[p].ch[x]=np,p=st[p].fa;}return;}//int np=last=newnode();st[np].len=st[p].len+1;while(p&&!st[p].ch[x])st[p].ch[x]=np,p=st[p].fa;if(!p)st[np].fa=1;else{int q=st[p].ch[x];if(st[p].len+1==st[q].len)st[np].fa=q;else{int nq=newnode();st[nq]=st[q]; st[nq].len=st[p].len+1;st[q].fa=st[np].fa=nq;while(p&&st[p].ch[x]==q)st[p].ch[x]=nq,p=st[p].fa;//向上把所有q都替换成nq}}
}
int find(int x) {return f[x]==x?x:f[x]=find(f[x]);
}
bool merge(int x,int y) {int xx=find(x),yy=find(y);if(xx!=yy) {f[xx]=yy;return true;}return false;
}
void init() {last=1;tot=0;newnode();for(int i=1;i<N;i++) {f[i]=i;}for(int i=1;i<N<<1;i++) {a[i]=i;}
}
int main()
{#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);memset(root,-1,sizeof(root));init();int n;read(n);for(int i=1;i<=n;i++) {last=1;scanf("%s",s+1);int len=strlen(s+1);for(int j=1;j<=len;j++) {add(s[j]-'a');id[last].push_back(i);}}for(int i=1;i<=tot;i++) {node[st[i].fa].push_back(i);}sort(a+1,a+1+tot,[&](int t1,int t2) {return st[t1].len>st[t2].len;});LL ans=0;for(int i=1;i<=tot;i++) {int u=a[i];int fa=-1;for(auto v:id[u]) {if(fa==-1) {fa=v;} else if(merge(fa,v)) {ans+=st[u].len;}}for(auto x:node[u]) {if(root[x]==-1) {continue;}if(fa==-1) {fa=root[x];} else if(merge(fa,root[x])) {ans+=st[u].len;}}root[u]=fa;}cout<<ans<<endl;return 0;
}

2021ICPC(澳门) - LCS Spanning Tree(广义后缀自动机)相关推荐

  1. BZOJ4545: DQS的trie 广义后缀自动机_LCT

    特别鸣神犇 fcwww 替我调出了无数个错误(没他的话我都快自闭了),祝大佬省选rp++ 板子题,给我写了一天QAQ...... 用 LCT 维护后缀树,暴力更新用 LCT 区间更新链即可 其实,在计 ...

  2. BZOJ3172lg3966 TJOI单词(广义后缀自动机)

    BZOJ3172&&lg3966 TJOI单词(广义后缀自动机) 题面 自己找去 HINT 给出多个文本串,让你查找每个文本串一共出现了多少次,广义后缀自动机建出parent tree ...

  3. 【BZOJ3926】[Zjoi2015]诸神眷顾的幻想乡 广义后缀自动机

    [BZOJ3926][Zjoi2015]诸神眷顾的幻想乡 Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝 ...

  4. BZOJ3277 串 【广义后缀自动机】

    Description 字符串是oi界常考的问题.现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中 至少k个字符串的子串(注意包括本身). Input 第一行两个整数n, ...

  5. 【bzoj5084】hashit 广义后缀自动机+树链的并+STL-set

    题目描述 你有一个字符串S,一开始为空串,要求支持两种操作 在S后面加入字母C 删除S最后一个字母 问每次操作后S有多少个两两不同的连续子串 输入 一行一个字符串Q,表示对S的操作 如果第i个字母是小 ...

  6. BZOJ5137lg4081(广义后缀自动机,set启发式合并)

    BZOJ5137&&lg4081(广义后缀自动机,set启发式合并) 题面 自己找去 HINT 给定多个文本串,让你查询每个文本串中有多少个本质不同的子串且这个子串只出现在当前这个文本 ...

  7. BZOJ.3277.串(广义后缀自动机)

    题目链接 \(Description\) 给定n个串和K,求每个串中有多少个子串是这n个串中至少K个串的子串. \(Solution\) 同上题,我们可以算出每个节点所代表的串出现在了几个串中:而且我 ...

  8. BZOJ-3473 (广义后缀自动机:拓扑 or 启发式合并)

    BZOJ-3473 (广义后缀自动机:拓扑 or 启发式合并) 题目链接 题意 nnn个字符串,询问每个字符串一共有几个子串至少出现在nnn个字符串中的kkk个 思路: 拓扑 建广义后缀自动机, dp ...

  9. BZOJ-2780 Sevenk Love Oimaster(广义后缀自动机)

    BZOJ-2780 Sevenk Love Oimaster(广义后缀自动机) 题目链接 题意 给出n个字符串,询问m个串一共出现在几个字符串中. 题解 广义后缀自动机板子题 将n个串建在一起,每次插 ...

最新文章

  1. [JavaScript] Map类型在JavaScript中的使用
  2. 自定义input type=file 样式的方法
  3. 在项目中谨慎为系统类添加分类!!!!!
  4. Spring AbstractAutowireCapableBeanFactory
  5. Permission denied (publickey). fatal: Could not read from remote repository.
  6. Liunx上训练模型的常见情况(不定期更新)
  7. Android 开发佳站3
  8. SPQuery 的若干.....小问题.......
  9. git rebase详解(图解+最简单示例,一次就懂)
  10. oracle回撤,Oracle使用排列组合计算最大回撤幅度
  11. 国科大五位本科生带“芯”毕业!平均年龄23.1岁,四个月主导完成64位RISC-V处理器SoC芯片设计并实现流片
  12. 桌面在计算机哪个文件,电脑桌面上的文件在C盘哪个文件里面
  13. 食物相克表食物最佳搭配
  14. 小程序 video 控制器外观调整_Razer Kishi 评测:吹破天的手机游戏控制器,真有那么好用吗?...
  15. DAC8568 Controller
  16. 天线巴伦制作和原理_巴伦的原理、设计、制作
  17. 网站收录链接分析之网站排名查询
  18. 【应急响应】————2、蠕虫病毒
  19. javascript简易留言板制作 -- 案例
  20. 【Python爬虫系列】为什么我喜欢python?来看看这些让人爱不释手的原因吧,购物网站大盘点,看过这些python做的项目,我立马入坑了…(神奇 | 爱了,爱了)

热门文章

  1. MySQL高级 - 案例 - 系统性能优化 - 分页优化
  2. 客户端从config上获取配置
  3. Dubbo的发展历史
  4. ConcurrentHashMap的源码分析-resizeStamp
  5. Spring5 源码下载注意事项
  6. Redis中的Sentinel 连接使用
  7. 文件下载乱码问题分析与解决
  8. jwt:token的解析
  9. 数据库-笛卡尔积-内连接
  10. 分隔线演练-利用参数增加分隔线的灵活度