3998: [TJOI2015]弦论

题目:传送门


题解:

   SAM的入门题目(很好的复习了SAM并加强Right集合的使用)

   其实对于第K小的字符串直接从root开始一通DFS就好,因为son边是直接根据字符存的呀,相当于自带字典序,直接从‘a' 开始找。

   一开始初始化一下从当前状态出发所能走的路径数(也就是能构成多少个字符串啦)

   然后根据T= 0/1分情况来处理Right集合大小:

   T== 0 :那Right集合大小就直接全部等于1咯

   T== 1  : 直接累加啊(原始操作)

   然后具体看代码注释吧:

  


代码:

 #include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
struct SAM
{
int son[],fail,dep;
}ch[];int cnt,last,root,a[];
void add(int k)
{
int x=a[k];
int p=last,np=++cnt;ch[np].dep=k;
while(p && ch[p].son[x]==)ch[p].son[x]=np,p=ch[p].fail;
if(p==)ch[np].fail=root;
else
{
int q=ch[p].son[x];
if(ch[p].dep+==ch[q].dep)ch[np].fail=q;
else
{
int nq=++cnt;
ch[nq]=ch[q];ch[nq].dep=ch[p].dep+;
ch[np].fail=ch[q].fail=nq;
while(p && ch[p].son[x]==q)ch[p].son[x]=nq,p=ch[p].fail;
}
}
last=np;
}
int len,T,k,Rsort[],r[],sa[],sum[];
char s[];
void dfs(int x)
{
if(k<=r[x])return ;
k-=r[x];//要从x继续往下搜,那么结束位置为x的子串一定会更优,那就减去这样的子串个数啊,r记录的就是这个
for(int i=;i<=;i++)
if(ch[x].son[i]!=)
{
int y=ch[x].son[i];
if(k>sum[y])k-=sum[y];//当前k如果比y可以走出来的路径还要多,那么第k小的一定不在y的路径上。由于是按照字典序小到大问的,那么y的路径一定比后面枚举的要优,那也要减,sum记录的就是可行路径数
else {printf("%c",i+'a');dfs(y);return ;}
}
}
int main()
{
cnt=;root=last=++cnt;
scanf("%s",s+);len=strlen(s+);
for(int i=;i<=len;i++)a[i]=s[i]-'a';
for(int i=;i<=len;i++)add(i);
scanf("%d%d",&T,&k);
for(int i=;i<=cnt;i++)Rsort[ch[i].dep]++;
for(int i=;i<=len;i++)Rsort[i]+=Rsort[i-];
for(int i=cnt;i>=;i--)sa[Rsort[ch[i].dep]--]=i;
for(int i=,p=root;i<=len;i++)p=ch[p].son[a[i]],r[p]++;
for(int i=cnt;i>=;i--)
if(T==)r[ch[sa[i]].fail]=;
else r[ch[sa[i]].fail]+=r[sa[i]];
r[root]=;
for(int i=cnt;i>=;i--)
{
int now=sa[i];sum[now]=r[now];
for(int j=;j<=;j++)if(ch[now].son[j]!=)sum[now]+=sum[ch[now].son[j]];
}
if(k>sum[root])printf("-1\n");
else dfs(root);
return ;
}

bzoj3998: [TJOI2015]弦论(SAM+dfs)的更多相关文章

  1. BZOJ3998:[TJOI2015]弦论(SAM)

    Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input 第一行是一个仅由小写英文字母构成的字符串S 第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个. ...

  2. [bzoj3998][TJOI2015]弦论_后缀自动机

    弦论 bzoj-3998 TJOI-2015 题目大意:给定一个字符串,求其$k$小子串. 注释:$1\le length \le 5\cdot 10^5$,$1\le k\le 10^9$. 想法: ...

  3. 【BZOJ 3998】 3998: [TJOI2015]弦论 (SAM )

    3998: [TJOI2015]弦论 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2627  Solved: 881 Description 对于一 ...

  4. luogu P3975 [TJOI2015]弦论 SAM

    luogu P3975 [TJOI2015]弦论 链接 bzoj 思路 建出sam. 子串算多个的,统计preant tree的子树大小,否则就是大小为1 然后再统计sam的节点能走到多少串. 然后就 ...

  5. [bzoj3998][TJOI2015]弦论-后缀自动机

    Brief Description 给定一个字符串, 您需要求出他的严格k小子串或非严格k小子串. Algorithm Design 考察使用后缀自动机. 首先原串建SAM, 然后如果考察每个状态代表 ...

  6. bzoj3998 [TJOI2015]弦论(SAM)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3998 [题意] 询问排名第k的子串是谁,0代表相同子串不同位置算作相同,1代表相同子串 ...

  7. 【BZOJ3998】弦论 [SAM]

    弦论 Time Limit: 10 Sec  Memory Limit: 256 MB[Submit][Status][Discuss] Description 对于一个给定长度为N的字符串,求它的第 ...

  8. BZOJ3998 TJOI2015弦论(后缀数组+二分答案)

    先看t=1的情况.显然得求出SA(因为我不会SAM).我们一位位地确定答案.设填到了第len位,二分这一位填什么之后,在已经确定的答案所在的范围(SA上的某段区间)内二分,找到最后一个小于当前串的后缀 ...

  9. BZOJ3998 TJOI2015弦论(后缀自动机)

    先考虑相同子串视为一个.按SAM的拓扑序预处理出从每个节点开始能得到多少个本质不同子串(注意虽然一个节点对应多个子串,但到达该点时当前的子串显然是确定为其中一个的),然后按位贪心即可. 相同子串视为多 ...

随机推荐

  1. NOIP 2013 T2 火柴排队 ---->求逆序对

    [NOIP2013T2]火柴排队 背景 noip2013day1 描述 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各 自 排成一列, 同一列火柴的高度互不相同, ...

  2. VS2005常用的快捷键分享

    VS2005代码编辑器的展开和折叠代码确实很方便和实用.以下是展开代码和折叠代码所用到的快捷键,很常用: Ctrl + M + O: 折叠所有方法 Ctrl + M + M: 折叠或者展开当前方法 C ...

  3. 利用JavaScript的if语句判断元素显示隐藏

    <html> <head> <meta charset="utf-8"> <title>无标题文档</title> &l ...

  4. SQL Server将数据导出到SQL脚本文件

    http://www.studyofnet.com/news/list-8883.2-1-4.html 一.SQL Server 2008将数据导出到SQL脚本文件 1.打开SQL Server200 ...

  5. 数据仓库模型建设基础及kimball建模方法总结

    观察数据的角度称之为维.决策数据市多为数据,多维数据分析是决策分析的组要内容. OLAP是在OLTP的基础上发展起来的,OLTP是以数据库为基础的,面对的是操作人员和底层管理人员,对基本数据进行查询和 ...

  6. ssh 免密码登入远程服务器

    生成ssh密钥,将公钥上传至远程服务器~/.ssh目录下面(没有的话就建一个): ssh-keygen -t rsa scp ~/.ssh/id_rsa.pub root@yourserver.com ...

  7. jquery 星级评价插件jquery Raty的使用

    需要引入的js <script type="text/javascript" src="<%=basePath%>resources/js/jquery ...

  8. Apex语言(二)变量与常量

    1.变量 凡是交给计算运算(处理)的数据就是变量,用来保存参加运算的数据和计算结果. 变量由变量名来标识. 变量名由字母数字和下划线组成,不能以数字开头. [正确]number,number1,num ...

  9. Ubuntu 16.04 安装 Django==1.11.8

    vim  InStall-Django.sh #!/bin/bash rm -rf /usr/bin/python ln -s /usr/bin/python3 /usr/bin/python mkd ...

  10. java 常用API 包装

    package com.oracel.demo01; public class Baozhuang { //将字符串转成基本数据类型 public static void main(String[] ...