QY 大神仙:这就是SAM大水题,快切快切

然而还没怎么理解SAM的我表示对着题解一脸懵逼

设原串为s;

对于后缀自动机上的一个点i,定义dp[i]为点i表示的字符串的答案(最长嵌套次数)

显然点i应从fa[i],fa[fa[i]]等endpos包含endpos(i)的节点转移过来,为什么呢?

因为后缀自动机的性质,fa[i]所代表的字符串都是i所代表的字符串的后缀(endpos),如果答案(嵌套的字符串)不包含s[endpos(i)]的话,就不用i去更新。

举个栗子(from here)

这里的4号节点,也就是(len最长的字符串)aab,它的father是1,也就是意味着它的答案没法更新(dp[4]=1)

可是aab里面有两个a,理论上答案是2,但因为3号节点(也就是aa)已经能通过fa[3]=2号节点来转移达到dp[3]=2;

所以4号节点需要管的转移只有它的后缀,也就是它的fa所包含的字符,真的只是fa[i]吗?注意到其实是fa[i],fa[fa[i]],fa[fa[fa[i]]]等fa树上一路跳上去的节点

好,那么我们得出(其实都是博主在瞎扯)点i只需从fa[i],fa[fa[i]]等节点转移过来,

由于字符串i嵌套字符串fa[i]肯定比嵌套字符串fa[fa[i]]难,所以我们记top[i]为i的fa树路径上最浅的dp值等于dp[i]的位置,也就是说从top[i]到i都没有嵌套来更新dp值

那么i就可以从top[fa]转移过来而不是从fa树上一路跳上去更新

那么还剩下具体的更新部分,也就是怎么判节点top[fa[a]]代表的字符串在节点a代表的字符串中出现了两次呢?

这里我们用endpos来判断,如果top[fa[a]]的至少两个endpos在a代表的最长字符串所覆盖的区间里出现过就成立

因为top[fa[a]]是a的后缀,所以肯定已经出现了一次,所以只要在(pos[a]-len[a]+len[top[fa[a]]],pos[a]-1)中出现过一次即可

等等,这是什么式子?

这里 pos[a]为a代表的最长字符串的最后一个字符在原串s中的位置,len[a]为a代表的最长字符串的长度

那么pos[a]-len[a]+1 到pos[a]即a代表的最长字符串所覆盖的区间,当然top[fa[a]]的endpos当然是不能在区间前len[top[fa[a]]-1的点出现的,不然还是越界

又因为top[fa[a]]的endpos在pos[a]肯定出现过一次所以要把这个点舍掉,那么这就是整个式子了

至于怎么维护一个节点的endpos集合,线段树合并即可。

(扯完了,上code):

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 400004
#define mid (l+r>>1)
using namespace std;
struct seg {int L[N*20],R[N*20],tot;void init() {tot=0;}void insert(int &now,int l,int r,int pos) {if(!now)now=++tot;if(l==r)return;if(pos<=mid)insert(L[now],l,mid,pos);else insert(R[now],mid+1,r,pos);}int merge(int A,int B) {if(!A||!B)return A+B;int it=++tot;L[it]=merge(L[A],L[B]);R[it]=merge(R[A],R[B]);return it;}int query(int now,int l,int r,int nl,int nr) {if(!now)return 0;if(nl<=l&&r<=nr)return 1;if(nl<=mid&&query(L[now],l,mid,nl,nr))return 1;if(mid<nr&&query(R[now],mid+1,r,nl,nr))return 1;return 0;}} aux;
int rt[N];
struct SAM {int cnt,las;int len[N],fa[N],ch[N][26],pos[N];void init() {cnt=las=1;}void add(int c,int pi) {int p=las,it=las=++cnt;len[it]=len[p]+1,pos[it]=pi;for(; p&&!ch[p][c]; p=fa[p])ch[p][c]=it;if(!p)fa[it]=1;else {int q=ch[p][c];if(len[q]==len[p]+1)fa[it]=q;else {int np=++cnt;for(int i=0; i<26; i++)ch[np][i]=ch[q][i];len[np]=len[p]+1,pos[np]=pos[q];fa[np]=fa[q],fa[q]=fa[it]=np;for(; p&&ch[p][c]==q; p=fa[p])ch[p][c]=np;}}}} sett;
void init() {sett.init(),aux.init();}
int n,tax[N],poi[N];
int dp[N],top[N];
char op[N];
int ans=1;
int main() {init();scanf("%d",&n);scanf("%s",op+1);for(int i=1; i<=n; i++) sett.add(op[i]-'a',i),aux.insert(rt[sett.las],1,n,i);for(int i=1; i<=sett.cnt; i++)tax[sett.len[i]]++;for(int i=1; i<=n; i++)tax[i]+=tax[i-1];for(int i=sett.cnt; i>=1; i--)poi[tax[sett.len[i]]--]=i;for(int i=sett.cnt; i>1; i--)      rt[sett.fa[poi[i]]]=aux.merge(rt[sett.fa[poi[i]]],rt[poi[i]]);for(int i=2; i<=sett.cnt; i++) {int u=poi[i],ff=sett.fa[u];if(ff==1)dp[u]=1,top[u]=u;else {if(aux.query(rt[top[ff]],1,n,sett.pos[u]-sett.len[u]+sett.len[top[ff]],sett.pos[u]-1))dp[u]=dp[ff]+1,top[u]=u,ans=max(ans,dp[u]);else dp[u]=dp[ff],top[u]=top[ff];}}printf("%d\n",ans);}//syktxdy
//qy dashenxian
//chc duliu

转载于:https://www.cnblogs.com/stepsys/p/10708983.html

[CF700E](Cool Slogans)相关推荐

  1. CF700E Cool Slogans

    CF700E Cool Slogans 给定一个字符串 S S S,要求构造字符串序列 s 1 , s 2 , - , s k s_1,s_2,-,s_k s1​,s2​,-,sk​满足任意 s i ...

  2. cf700E. Cool Slogans

    题解: 首先建出后缀自动机 我们考虑对于每个节点i 在其parent树上找到离其最近的j让s[j]子串在s[i]中出现>=2次以上(因为在j祖先节点必然都满足条件 但显然最近的最优) 所以把原p ...

  3. CF700E Cool Slogans(SAM,dp)

    解析 好题. 首先,我们每次都令 sis_isi​ 是 si+1s_{i+1}si+1​ 的后缀,肯定是不劣的 问题就可以转化到 fail 树上了 首先肯定要线段树合并处理出endpos集合 朴素想法 ...

  4. 2020.6月做题记录

    长期计划 SAM专题 date:2020.05.21-2020.06.01 基础类: Problem Finished P3804 [模板]后缀自动机 (SAM) √√√ SP1811 LCS - L ...

  5. CF700E E. Cool Slogans

    https://codeforces.com/contest/700/problem/E 题解:https://www.luogu.org/problemnew/solution/CF700E 其实就 ...

  6. 【CF700E】Cool Slogans【后缀自动机】【可持久化线段树合并】【树上倍增】

    传送门 题意:给定字符串SSS,求一堆字符串s1,s2,s3,...,sks_1,s_2,s_3,...,s_ks1​,s2​,s3​,...,sk​,满足s1s_1s1​是SSS的子串,且sis_i ...

  7. Cool Slogans[CF700E][后缀自动机][Dp]

    文章目录 题目 思路 代码 题目 Luogu n ≤ 2 ⋅ 1 0 5 n\le 2\cdot 10^5 n≤2⋅105 思路 性质: ∃ s i \exist\quad s_i ∃si​ 是 s ...

  8. [LOJ 6288]猫咪[CF 700E]Cool Slogans

    [LOJ 6288]猫咪[CF 700E]Cool Slogans 题意 给定一个字符串 \(T\), 求一个最大的 \(K\) 使得存在 \(S_1,S_2,\dots,S_k\) 满足 \(S_1 ...

  9. CF700E-Cool Slogans【SAM,线段树合并,dp】

    正题 题目链接:https://www.luogu.com.cn/problem/CF700E 题目大意 给出一个字符串SSS,求一个最大的kkk使得存在kkk个字符串其中s1s_1s1​是SSS的子 ...

最新文章

  1. 7.Set集合总结(TreeSet集合和HashSet集合)
  2. css中.和#的区别 不写时代表什么
  3. 软件著作权 开源框架_开源软件分享-基于.net core 3.1的快速开发框架
  4. centos7 怎么封装自己的镜像_「10」-CentOS7.5(1804)
  5. 联想确认再次裁员 称调整主要分布在海外
  6. java.lang.IllegalArgumentException: requirement failed: No output operations registered, so nothing
  7. CentOS/RHEL6.5中使用WordPress快速建站
  8. SAP CRM customer classfication debug
  9. 教你在Yii2.0框架中如何创建自定义小部件
  10. 基于MNIST数据集的不同权重初始值的比较
  11. 【操作系统/OS笔记15】死锁的系统模型,死锁的处理办法,银行家算法与死锁检验算法
  12. 数据库事务4种隔离级别和7种传播行为
  13. [BX]和loop指令06 - 零基础入门学习汇编语言28
  14. 如何调用畅捷通接口_用友金蝶多组织多账套的不同数据如何合并?
  15. 微信小程序学习(跟着b站的黑马程序员视频所学)
  16. mysql pxc介绍_MySQL高可用之PXC简介
  17. 外接圆、内切圆半径公式及对应关系知识点总结
  18. 前端开发工程师需要的技能
  19. 2021年山东省职业院校技能大赛中职组网络安全赛项竞赛样题
  20. 录制课件时,小米笔记本电脑,外接耳麦, 麦克风没那有声音,怎么办?

热门文章

  1. 数据挖掘关联规则Apriori算法
  2. PTA-支票面额(C语言)
  3. MySQL开发技巧——批量数据入库及检索
  4. [CF 821E] Okabe and El Psy Kongroo
  5. python队列操作
  6. vim\neovim美化 + 终端美化配置
  7. win10备份为wim_无惧UEFI, Win10也能玩转一键自动还原
  8. 平安科技招聘专场| 15-30k! 大厂9大热门技术岗位任你选!
  9. 一张图了解python基本语法_一张图认识Python(附基本语法总结)
  10. Could not extract response: no suitable HttpMessageConverter found for response type ***