题目链接

https://www.luogu.com.cn/problem/P3975

题解

此题非常经典且重要,是sam的函谷关,必须拿下。

  • 记录每个点endpos大小的方法是在parent树从下往上递推。开始的is_pre就是看看当前点与没有包含原串前缀,有的话,这个会在parent tree分叉时候丢掉。也就是当前节点并不是所有子节点的endpos的并集,并集还得加上那个前缀的结束位置才是当前点的endpos集合。
  • 求endpos大小的dp非常经典。
  • dp数组表示从某个点出发沿自动机往下走的子串有多少。每个点一部分子串是出边的字符加上自动机下一个状态的字符串形成的串(dp[nex]),一部分是边字符自己形成的串(endpos[nex])。(以上dp是算相同的)。
  • 之后像搜索树一样在自动机上搜索。注意往下走的时候也会消耗一定数量的串。
  • 天津oi的风格就是数据结构模板题。看看代码就懂了。

AC代码

#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
const int NN=5e5+10;
struct NODE
{int ch[26];int len,fa;NODE(){memset(ch,0,sizeof(ch));len=0;}
}dian[NN<<1];
int is_pre[NN<<1];//标记是否是前缀
int las=1,tot=1;
void add(int c)
{int p=las;int np=las=++tot;is_pre[np]=1;//endpos[np]={i} where s[i]=cdian[np].len=dian[p].len+1;for(;p&&!dian[p].ch[c];p=dian[p].fa)dian[p].ch[c]=np;if(!p){dian[np].fa=1;}//以上为case 1else{int q=dian[p].ch[c];if(dian[q].len==dian[p].len+1)dian[np].fa=q;//以上为case 2else{int nq=++tot;dian[nq]=dian[q];//endpos不是i了dian[nq].len=dian[p].len+1;dian[q].fa=dian[np].fa=nq; for(;p&&dian[p].ch[c]==q;p=dian[p].fa)dian[p].ch[c]=nq;//以上为case 3}}
}
int n;
vector<int>parentcon[NN<<1];
char s[NN];
void sam(){las=1,tot=1;for(int i=1;i<(n<<1);i++)is_pre[i]=0;for(int i=1;i<=n;i++)add(s[i]-'a');for(int i=1;i<=tot;i++){parentcon[dian[i].fa].push_back(i);}
}
long long endpos[NN<<1],dp[NN<<1];
void get_endpos(int cur,int fa){int up=parentcon[cur].size();endpos[cur]=is_pre[cur];for(int i=0;i<up;i++){int nex=parentcon[cur][i];if(nex!=fa){get_endpos(nex,fa);endpos[cur]+=endpos[nex];}}
}
void get_num(int cur){//算相同if(dp[cur])return;dp[cur]=0;for(int i=0;i<26;i++){int nex=dian[cur].ch[i];if(nex){get_num(nex);dp[cur]+=dp[nex]+endpos[nex];//dp[nex]是i+xxx的数量,endpos[nex]是i的数量,dp不含空串}}
}
void get_num_dif(int cur){//不算相同if(dp[cur])return;dp[cur]=1;//含空串for(int i=0;i<26;i++){int nex=dian[cur].ch[i];if(nex){get_num_dif(nex);dp[cur]+=dp[nex];}}
}
int ans[NN],anslen;
int t;
int dfs(int cur,int k,int deep){if(k<=0){anslen=deep-1;return k;}for(int i=0;i<26;i++){int nex=dian[cur].ch[i];if(nex){int simp=(t?endpos[nex]:1);if(dp[nex]+simp>=k){ans[deep]=i;return dfs(nex,k-simp,deep+1);break;}else{k-=(dp[nex]+simp);}}}return k;
}int len;
int main()
{scanf("%s",s+1);n=strlen(s+1);sam();int k;scanf("%d%d",&t,&k);memset(dp,0,sizeof(dp));memset(endpos,0,sizeof(endpos));if(t==1){get_endpos(1,0);get_num(1);if(k>dp[1])printf("-1\n");else{dfs(1,k,1);for(int i=1;i<=anslen;i++)printf("%c",ans[i]+'a');printf("\n");}}else{get_num_dif(1);for(int i=1;i<=tot;i++)dp[i]--;//去空串if(k>dp[1])printf("-1\n");else{dfs(1,k,1);for(int i=1;i<=anslen;i++)printf("%c",ans[i]+'a');printf("\n");}}return 0;
}

洛谷P3975【天津省选2015】(后缀自动机DP)相关推荐

  1. 【洛谷 P3975】 [TJOI2015]弦论(后缀自动机)

    题目链接 建出后缀自动机. T=0,每个子串算一次,否则每个子串算该子串的\(endpos\)集合大小次. 用\(f[i]\)表示结点\(i\)表示的\(endpos\)集合大小,则\(f[i]\)为 ...

  2. 洛谷 P4070 [SDOI2016]生成魔咒 后缀自动机

    题目描述 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1.2 拼凑起来形成一个魔咒串 [1,2]. 一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒. 例如 S=[1, ...

  3. 洛谷 [P3975 [TJOI2015]弦论

    洛谷 P3975 [TJOI2015]弦论 题目描述 给定一个长度为 nnn 的字符串,求它的第 kkk 小字串:给定 ttt, ttt 为 000 则表示不同位置的相同子串算作一个,ttt 为 11 ...

  4. 洛谷-P3975 弦论(后缀自动机板子题)

    弦论 一道板子题,让我感觉板子题都还不会...然后把递推写成dfs时没有给string加上&,导致内存爆了,2333,果然还是传引用好 题意:求字典序第K小子串以及本质不同的第K小子串 思路: ...

  5. 洛谷 P3975 [TJOI2015]弦论 解题报告

    P3975 [TJOI2015]弦论 题目描述 为了提高智商,ZJY开始学习弦论.这一天,她在<String theory>中看到了这样一道问题:对于一个给定的长度为\(n\)的字符串,求 ...

  6. 洛谷P3975 弦论

    题意:求一个串的字典序第k小的子串/本质不同第k小的子串. 解:一开始我的想法是在后缀树上找,但是不知道后缀树上的边对应的是哪些字符... 然而可以不用fail树转移,用转移边转移即可. 先建一个后缀 ...

  7. 洛谷P3975 - [TJOI2015]弦论

    Portal Description 给出一个小写字母串\(s(|s|\leq5\times10^5),t\in\{0,1\},k(k\leq10^9)\),求\(s\)的第\(k\)小子串.\(t= ...

  8. 洛谷:P4516 [JSOI2018] 潜入行动(树形dp、树上分组背包统计方案数)

    潜入行动 题意: 在树上每个点可以放置监控设备,监控该点周围的点(不包括该点),问刚好放置 k 个监控设备监控使得整棵树所有点都被监控的方案数是多少. 思路: 显然是个树形dp,k个监控自然联想分组背 ...

  9. 洛谷P4338 [ZJOI2018]历史(LCT,树形DP,树链剖分)

    洛谷题目传送门 ZJOI的考场上最弱外省选手T2 10分成功滚粗...... 首先要想到30分的结论 说实话Day1前几天刚刚刚掉了SDOI2017的树点涂色,考场上也想到了这一点 想到了又有什么用? ...

  10. hdu5343 后缀自动机+dp

    给定两个串,分别截取字串X和Y,连接组成X+Y,求不同的X+Y的方案数. 对于X+Y,如果重复的部分其实就是从同一个X+Y的某个地方断开弄成不同的X和Y,那么只要使得X和X+Y匹配得最长就行了. 因此 ...

最新文章

  1. 2022-2028年中国电力行业节能减排投资分析及前景预测报告
  2. oracle define (hex 26),oracle 特殊字符轉義
  3. SQL开发好助手—SQL Assistant 5
  4. mysql 2027_阿里云mysql远程登录报ERROR 2027(HY000)
  5. 关于使用rem单位,calc()进行自适应布局
  6. EF架构~将数据库注释添加导入到模型实体类中
  7. apache+fastcgi+php
  8. 九连环问题c语言程序,九连环游戏的算法源代码
  9. 写给准备看CCNA题库的朋友们 希望有些帮助
  10. 北航计算机学院考研复试,北航计算机学院考研复试-北京航空航天大学计算机学院2015年考研复试方法...
  11. 产品经理为什么比程序员工资要高?百度员工:因为他是产品灵魂
  12. S7-1200使用集成库FB285控制G120变频器的基本步骤
  13. 学习java和html必须要知道的英文单词(入门单词,包括C#)
  14. 获取小程序码所携带的参数
  15. 华为:证实已开发出自主操作系统
  16. BPM软件_财务报销流程管理解决方案_K2工作流引擎
  17. MySQL字段类型与Java中类型的对应
  18. 【计算机视觉40例】案例38:驾驶员疲劳监测
  19. 信息技术课程计算机硬件,初中信息技术课程关键思路分析
  20. go 获得 mysql 实际运行 SQL_mysql对标准sql的goup by进行了扩展 | 学步园

热门文章

  1. SQL 语句的类型和 用法
  2. 混合云市场现状与发展趋势研究
  3. 《流浪地球》后续,深度对话刘慈欣:地球只是太空中的一粒尘埃
  4. 嵌入式应用-详解移植并使用freetype显示文字
  5. 计算机原理论文2000字,计算机原理论文_计算机论文3000字_对计算机的认识论文...
  6. sqlserver设计表不允许保存更改,阻止保存要求重新创建表的更改
  7. Life with qmail -- 中文版(英文版本2 Jan 2006)
  8. Redis学习笔记(B站狂神说)(自己总结方便复习)
  9. 8421BCD码 5421BCD码 余三码 格雷码 余三循环码之间的关系,转换以及简易方法
  10. 杰里之AC695N/AC696N 蓝牙耳机PCB LAYOUT 说明【篇3】