题意:给定一个长度为n的下标从0开始的小写字母字符串,每次对于当前的i寻找一个j使得后缀i与后缀j的lcp最大,(j<i)若lcp相同则取较小的

若lcp为0则输出0与当前字符,i自增1,否则输出lcp的值与j,i自增lcp的值,以上过程重复直到i>=n

要求模拟这个过程

n<=1e5,sigma n<=2e6

思路:显然后缀的lcp要用到后缀数组

考虑对于每一个i都直接枚举j不可做,对于rank而言可以预处理出每一段连续的height大于0的起始位置和结束位置,在段中往左右两侧暴力枚举

满足要求的条件为:sa[j]<i,且连续的height的min的值不减

这个暴力扫描的复杂度应该假了(真的吗),但数据卡不掉……

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<iostream>
  4. #include<algorithm>
  5. typedef long long ll;
  6. using namespace std;
  7. #define N 110000
  8. #define oo 10000000
  9. #define MOD 100000073
  10.  
  11. char ch[N];
  12. int n,i,s[N],sa[N],wa[N],wb[N],wc[N],wd[N],height[N],Rank[N],pre[N],nxt[N];
  13.  
  14. bool cmp(int *r,int a,int b,int l)
  15. {
  16. return r[a]==r[b]&&r[a+l]==r[b+l];
  17. }
  18.  
  19. void getsa(int *r,int *sa,int n,int m)
  20. {
  21. int *x=wa,*y=wb,j,p;
  22. for(i=;i<n;i++) wc[x[i]=r[i]]++;
  23. for(i=;i<m;i++) wc[i]+=wc[i-];
  24. for(i=n-;i>=;i--) sa[--wc[x[i]]]=i;
  25. for(j=,p=;p<n;j*=,m=p)
  26. {
  27. p=;
  28. for(i=n-j;i<n;i++) y[p++]=i;
  29. for(i=;i<n;i++)
  30. if(sa[i]>=j) y[p++]=sa[i]-j;
  31. for(i=;i<n;i++) wd[i]=x[y[i]];
  32. for(i=;i<m;i++) wc[i]=;
  33. for(i=;i<n;i++) wc[wd[i]]++;
  34. for(i=;i<m;i++) wc[i]+=wc[i-];
  35. for(i=n-;i>=;i--) sa[--wc[wd[i]]]=y[i];
  36. swap(x,y);
  37. p=; x[sa[]]=;
  38. for(i=;i<n;i++) x[sa[i]]=cmp(y,sa[i-],sa[i],j)?p-:p++;
  39. if(j>n) break;
  40. }
  41. }
  42.  
  43. void getheight(int *r,int *sa,int n)
  44. {
  45. int i,j,k=;
  46. for(i=;i<=n;i++) Rank[sa[i]]=i;
  47. for(i=;i<n;height[Rank[i++]]=k)
  48. {
  49. if(k) k--;
  50. j=sa[Rank[i]-];
  51. while(r[i+k]==r[j+k]) k++;
  52. }
  53. }
  54.  
  55. void init()
  56. {
  57. memset(s,,sizeof(s));
  58. memset(sa,,sizeof(sa));
  59. memset(wa,,sizeof(wa));
  60. memset(wb,,sizeof(wb));
  61. memset(wc,,sizeof(wc));
  62. memset(wd,,sizeof(wd));
  63. memset(height,,sizeof(height));
  64. memset(Rank,,sizeof(Rank));
  65. }
  66.  
  67. int main()
  68. {
  69. int cas;
  70. scanf("%d",&cas);
  71. for(int v=;v<=cas;v++)
  72. {
  73. init();
  74. printf("Case #%d:\n",v);
  75. scanf("%s",ch);
  76. n=strlen(ch);
  77. for(int i=;i<n;i++) s[i]=ch[i]-'a'+;
  78. s[n]=;
  79. getsa(s,sa,n+,);
  80. getheight(s,sa,n);
  81. for(int i=;i<=n;i++)
  82. if(!height[i]) pre[i]=i;
  83. else pre[i]=pre[i-];
  84. for(int i=n;i>=;i--)
  85. if(height[i+]==||i==n) nxt[i]=i;
  86. else nxt[i]=nxt[i+];
  87. int i=;
  88. while(i<n)
  89. {
  90. int now=Rank[i];
  91. int k=;
  92. int t=i;
  93. int mn=height[now];
  94. for(int j=now-;j>=pre[now];j--)
  95. {
  96. mn=min(mn,height[j+]);
  97. if(mn<k) break;
  98. if(sa[j]<i)
  99. {
  100. if(mn>k||mn==k&&sa[j]<t)
  101. {
  102. k=mn; t=sa[j];
  103. }
  104. }
  105. }
  106. if(now+<=nxt[now]) mn=height[now+];
  107. for(int j=now+;j<=nxt[now];j++)
  108. {
  109. mn=min(mn,height[j]);
  110. if(mn<k) break;
  111. if(sa[j]<i)
  112. {
  113. if(mn>k||mn==k&&sa[j]<t)
  114. {
  115. k=mn; t=sa[j];
  116. }
  117. }
  118. }
  119. if(!k)
  120. {
  121. printf("-1 %d\n",ch[i]);
  122. i++;
  123. }
  124. else
  125. {
  126. printf("%d %d\n",k,t);
  127. i+=k;
  128. }
  129. }
  130. }
  131. return ;
  132. }

【HDOJ5558】Alice's Classified Message(后缀数组)的更多相关文章

  1. (HDU 5558) 2015ACM/ICPC亚洲区合肥站---Alice's Classified Message(后缀数组)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5558 Problem Description Alice wants to send a classi ...

  2. HUID 5558 Alice's Classified Message 后缀数组+单调栈+二分

    http://acm.hdu.edu.cn/showproblem.php?pid=5558 对于每个后缀suffix(i),想要在前面i - 1个suffix中找到一个pos,使得LCP最大.这样做 ...

  3. HDU 5558 Alice's Classified Message(后缀数组+二分+rmq(+线段树?))

    题意 大概就是给你一个串,对于每个\(i\),在\([1,i-1]\)中找到一个\(j\),使得\(lcp(i,j)\)最长,若有多个最大\(j\)选最小,求\(j\)和这个\(lcp\)长度 思路 ...

  4. hdu5558 Alice's Classified Message

    地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=5558 题目: Alice's Classified Message Time Limit: 1 ...

  5. HDU5558 Alice's Classified Message(合肥区域赛 后缀数组)

    当初合肥区域赛的题(现场赛改了数据范围就暴力过了),可惜当初后缀数组算法的名字都没听过,现在重做下. i从1到n - 1,每次枚举rank[i]附近的排名,并记录当起点小于i时的LCP(rank[i] ...

  6. POJ 2774 Long Long Message 后缀数组

    Long Long Message   Description The little cat is majoring in physics in the capital of Byterland. A ...

  7. poj 2774 Long Long Message 后缀数组基础题

    Time Limit: 4000MS   Memory Limit: 131072K Total Submissions: 24756   Accepted: 10130 Case Time Limi ...

  8. POJ2774Long Long Message (后缀数组&后缀自动机)

    问题: The little cat is majoring in physics in the capital of Byterland. A piece of sad news comes to ...

  9. POJ2774 Long Long Message —— 后缀数组 两字符串的最长公共子串

    题目链接:https://vjudge.net/problem/POJ-2774 Long Long Message Time Limit: 4000MS   Memory Limit: 131072 ...

随机推荐

  1. 【Ecshop】修改处理用户购物车的行为

    Ecshop v2.7.3的购物车处理方面在现在看来有比较反用户体验的设计: 用户未登录时加入购物车的商品,在用户登录后会被清空而不是加入到登录用户的购物车中: 用户登录后加入购物车的商品,在退出后会 ...

  2. JZOJ 4307. 喝喝喝

    Description

  3. kubernetes dashboard permission errors

    kubernetes dashboard 的权限错误 warning configmaps is forbidden: User "system:serviceaccount:kube-sy ...

  4. linux系统下单节点hadoop2的配置

    Jdk安装: jdk-7u45-linux-x64.gz cp jdk-7u45-linux-x64.gz /usr/java/ cd /usr/java/ tar -zxvf jdk-7u45-li ...

  5. Linux程序编辑器

    重点回顾:Linux底下的配置文件多为文本文件,故使用vim即可进行设定编辑: vim可视为程序编辑器,可用以编辑shell script,配置文件等,避免打错字 vi为所有unix like的操作系 ...

  6. ObjectOutputStream和ObjectInputStream的简单使用

    使用ObjectOutputStream往文本写内容时,首先在文本里面标记开始,然后是内容,最后加上结束标示.如果想再次往文本里面添加内容的话,就要加在开始标示之后和结束标示之前,不然会读取不到写入的 ...

  7. JVM内存管理:深入Java内存区域与OOM

    Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 概述: 对于从事C.C++程序开发的开发人员来说,在内存管理领域,他们即是拥有最高权力的皇帝 ...

  8. scripts

    Shell Script:================================================================ 示例1:[root@server0 ~]# ...

  9. [译]pandas .at 和.loc速度对比

    df.at 一次只能访问一个值. df.loc能够选取多行多列. In [25]: %timeit df.loc[('a', 'A'), ('c', 'C')] 10000 loops, best o ...

  10. 项目中遇到的ts问题汇总

    报错关键词句 报错截图 解决 Declaration of public static field not allowed after declaration of public instance m ...