https://ac.nowcoder.com/acm/contest/625/K

题意:

给出Q 个询问 i , 求 s[0..i-1] 与 s[i...len-1] 有多少相同的字串

分析:

给出了查询 , 容易想到先预处理出答案好吧 , 字符串的问题也容易想到后缀自动机 ,但是我们该怎么使用呢?

下面提供我的思路;

我们建立出SAM后 , 跑一边拓扑排序 ,根据SAM跑出来的拓扑排序的序列特性 , 我们可以求出 在当前状态st 的最大串字符出现的个数

  1. for (int i = now; i >= ; --i) {///得到的是最大字符串的出现次数
  2. int x = rank[i];
  3. endpos[slink[x]] += endpos[x];
  4. }

可是这次我们需要求的是相同的串有多少 , 我们不可以暴力出SAM里面存有的串的个数 , 现在就来搞一个很奇妙的东西,

我们可以根据上面求出来的endpos , 去推出 有多少相同的字符串;

  1. for(int i= ; i<=now; i++)///得到全部串的出现次数
  2. {
  3. int x=rank[i]; ///到x这个状态时 , 有多少的后缀总共串
  4. sum[x] = sum[slink[x]] + endpos[x]*(maxlen[x] - maxlen[slink[x]]);
  5. //cout<<sum[x]<<endl;
  6. }

我们知道 对于 now1 , 与now2=slink[now1] , 如果now1状态出现了 , 那么now2 的状态也肯定会出现 , 因为silnk 是链接now1接下去的后缀 ,也就是说now2 是now1的后缀

所以我们求当前now 有多少串相同的时候 , 就要+上一个的后缀价值 sum[x] = sum[slink[x]】 + 当前的价值

当前的价值又是 怎么计算呢?

我们知道 maxlen[x] - maxlen[slink[x]]  是表示当前的状态x 里面有多少的串 , 那这个状态出现的次数与包含的串相乘 , 不就是当前我们需要求的价值了吗

上面可能说的比较乱 , 主要是我巨菜不知如何表达鸭

上面是用str1 串去构建的SAM , 然后用str2 在这个自动机里面跑 , 与求LCA 很相似

可以参考https://www.cnblogs.com/shuaihui520/p/10686862.html

  1. #include <bits/stdc++.h>
  2. #define LL long long
  3. #define P pair<int, int>
  4. #define lowbit(x) (x & -x)
  5. #define mem(a, b) memset(a, b, sizeof(a))
  6. #define rep(i, a, n) for (int i = a; i <= n; ++i)
  7. #define mid ((l + r) >> 1)
  8. #define lc rt<<1
  9. #define rc rt<<1|1
  10. #define ll long long
  11. using namespace std;
  12. const int maxn = ;
  13. struct SAM{
  14.  
  15. int trans[maxn<<][], slink[maxn<<], maxlen[maxn<<];
  16. // 用来求endpos
  17. int indegree[maxn<<], endpos[maxn<<], rank[maxn<<], ans[maxn<<];
  18. // 计算所有子串的和(0-9表示)
  19. LL sum[maxn<<],D[maxn];
  20. int last, now, root;
  21.  
  22. inline void newnode (int v) {
  23. maxlen[++now] = v;
  24. mem(trans[now],);
  25. }
  26.  
  27. inline void extend(int c) {
  28. newnode(maxlen[last] + );
  29. int p = last, np = now;
  30. // 更新trans
  31. while (p && !trans[p][c]) {
  32. trans[p][c] = np;
  33. p = slink[p];
  34. }
  35. if (!p) slink[np] = root;
  36. else {
  37. int q = trans[p][c];
  38. if (maxlen[p] + != maxlen[q]) {
  39. // 将q点拆出nq,使得maxlen[p] + 1 == maxlen[q]
  40. newnode(maxlen[p] + );
  41. int nq = now;
  42. memcpy(trans[nq], trans[q], sizeof(trans[q]));
  43. slink[nq] = slink[q];
  44. slink[q] = slink[np] = nq;
  45. while (p && trans[p][c] == q) {
  46. trans[p][c] = nq;
  47. p = slink[p];
  48. }
  49. }else slink[np] = q;
  50. }
  51. last = np;
  52. // 初始状态为可接受状态
  53. endpos[np] = ;
  54. }
  55.  
  56. inline void init()
  57. {
  58. root = last = now = ;
  59. slink[root]=;
  60. mem(trans[root],);
  61. mem(endpos,);
  62. mem(sum,);
  63. mem(indegree,);
  64. mem(rank,);
  65. }
  66.  
  67. inline void getEndpos() {
  68. // topsort
  69. for (int i = ; i <= now; ++i) indegree[ maxlen[i] ]++; // 统计相同度数的节点的个数
  70. for (int i = ; i <= now; ++i) indegree[i] += indegree[i-]; // 统计度数小于等于 i 的节点的总数
  71. for (int i = ; i <= now; ++i) rank[ indegree[ maxlen[i] ]-- ] = i; // 为每个节点编号,节点度数越大编号越靠后
  72. // 从下往上按照slik更新
  73. for (int i = now; i >= ; --i) {///得到的是最大字符串的出现次数
  74. int x = rank[i];
  75. endpos[slink[x]] += endpos[x];
  76. }
  77. for(int i= ; i<=now; i++)///得到全部串的出现次数
  78. {
  79. int x=rank[i]; ///到x这个状态时 , 有多少的后缀总共串
  80. sum[x] = sum[slink[x]] + endpos[x]*(maxlen[x] - maxlen[slink[x]]);
  81. //cout<<sum[x]<<endl;
  82. }
  83. }
  84. ///用一个串去跑的自动机
  85. inline void work(string s,int W)
  86. {
  87. getEndpos();
  88. int len=s.size();
  89. int now=root;
  90. int t1=;
  91. ll ret=;
  92. for(int i= ; i<len ; i++)
  93. {
  94. int nowid=s[i]-'a';
  95. if(trans[now][nowid])///这个状态有了 , 去下一个状态找
  96. {
  97. t1++;
  98. now=trans[now][nowid];
  99. //ret+=sum[slink[now]] + endpos[now]*(t1-maxlen[slink[now]]);
  100. }
  101. else
  102. { while(now!= && trans[now][nowid]==) {now=slink[now];}///缩小范围找满足条件的
  103.  
  104. if(now)
  105. {
  106. t1 = maxlen[now]+;
  107. now=trans[now][nowid];
  108.  
  109. }
  110. else
  111. {
  112. t1=;now=root;
  113. }
  114. }
  115. ret+=sum[slink[now]] + endpos[now]*(t1-maxlen[slink[now]]);
  116. }
  117. D[W]=ret;
  118. //return ret;
  119. }
  120.  
  121. }sam;
  122.  
  123. int main()
  124. {
  125.  
  126. string T;cin>>T;
  127. int len=T.size();
  128.  
  129. for(int i= ; i<len ; i++)
  130. {
  131. string t2;
  132. sam.init();
  133. for(int j= ; j<i ; j++)
  134. {
  135. sam.extend(T[j]-'a');
  136. }
  137.  
  138. for(int j=i ; j<len ; j++)
  139. {
  140. t2+=T[j];
  141. }
  142. sam.work(t2,i);
  143.  
  144. }
  145. int E;scanf("%d",&E);
  146. while(E--)
  147. {
  148. int x;
  149. scanf("%d",&x);
  150. printf("%lld\n",sam.D[x]);
  151. }
  152.  
  153. //- sam.all();
  154. }

2019年华南理工大学程序设计竞赛(春季赛) K Parco_Love_String(后缀自动机)找两个串的相同字串有多少的更多相关文章

  1. A NB群友 【记忆化搜索】(2019年华南理工大学程序设计竞赛(春季赛))

    冲鸭!去刷题:https://ac.nowcoder.com/acm/contest/625/A 题目描述 CC是著名的算法竞赛选手,他不仅人长得帅,而且技术了得,自然而然就有了许多粉丝. 为了能帮助 ...

  2. 2019年华南理工大学程序设计竞赛(春季赛)-C-六学家的困惑

    题目链接:https://ac.nowcoder.com/acm/contest/625/C 题意:给定两个字符串,每次只能从两个字符串的两端取字符,求依次取字符后所构成的数字最大为多少. 思路:思路 ...

  3. 2019年华南理工大学程序设计竞赛(春季赛)-H-Parco_Love_GCD

    题目链接:https://ac.nowcoder.com/acm/contest/625/H 题意:给定n个数(<=1e9)的序列,其中n<=5e5,求该序列所有子序列的对应的gcd对1e ...

  4. C 六学家的困惑 【YY】 (2019年华南理工大学程序设计竞赛(春季赛))

    冲鸭,去刷题:https://ac.nowcoder.com/acm/contest/625/C 小六喜欢两全其美的事情,今天就正好有一个这样的机会. 小六面前有两根管子,管子里面放满了数字为1到9的 ...

  5. 2019年华南理工大学程序设计竞赛(春季赛) B 修仙时在做什么?有没有空?可以来炼丹吗?(思维建图搜索)

    https://ac.nowcoder.com/acm/contest/625/B 分析: 全部的状态只有1<<18 个 , 所以我们可以预处理 f[u][j] , 然后建立出全部的u可以 ...

  6. 2019年华南理工大学程序设计竞赛(春季赛)A NB群友

    https://ac.nowcoder.com/acm/contest/625/A 题意:给出一个区间范围 , 求有多少个数的每一位的积是在这个区间里面的 分析:没错了 ,就是记忆化暴力搜索 ,不断的 ...

  7. 2018华南理工大学程序设计竞赛 H-对称与反对称

    H-对称与反对称 题目描述 给出一个N*N的方阵A.构造方阵B,C: 使得A = B + C.其中 B为对称矩阵,C为反对称矩阵. 对于方阵S中的任意元素,若(S)ij = (S)ji,则称S为对称矩 ...

  8. “景驰科技杯”2018年华南理工大学程序设计竞赛 B. 一级棒!(并查集)

    题目链接:https://www.nowcoder.com/acm/contest/94/B 题意:在一棵有 n 个节点的树上,有两种操作,一个是把 u 到 v 的路径走一遍,另一个是查询 u 到 f ...

  9. “景驰科技杯”2018年华南理工大学程序设计竞赛 A. 欧洲爆破(思维+期望+状压DP)

    题目链接:https://www.nowcoder.com/acm/contest/94/A 题意:在一个二维平面上有 n 个炸弹,每个炸弹有一个坐标和爆炸半径,引爆它之后在其半径范围内的炸弹也会爆炸 ...

随机推荐

  1. [SoapUI] 通过SoapUI发送POST请求,请求的body是JSON格式的数据

    通过SoapUI发送POST请求,请求的body是JSON格式的数据: data={"currentDate":"2015-06-19","reset ...

  2. 利用crosstool-ng自动化编译交叉编译环境(转)

    原文地址:http://www.bootc.net/archives/2012/05/26/how-to-build-a-cross-compiler-for-your-raspberry-pi/ A ...

  3. mongodb 查询条件

    这节来说说mongodb条件操作符,"$lt", "$lte", "$gt", "$gte", "$ne&qu ...

  4. 选项“6”对 /langversion 无效;必须是 ISO-1、ISO-2、3、4、5 或 Default

    部署MVC的时候,因为服务器.NET版本是4.5.1,所以在vs将.NET版本降到4.5.1的时候发布报错. 原因:C#6降到C#5导致 解决办法:修改web.config配置 ,编译选项改为comp ...

  5. [GO]获取命令行参数

    package main import ( "os" "fmt" ) func main() { list := os.Args n := len(list) ...

  6. javascript总结系列49:javaScript教程:原型链不可变

    <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8& ...

  7. 简单引入logback

    pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w ...

  8. linux安装x264 ffmpeg

    1. 安装yasm 2. 安装x264 3. 安装ffmpeg 安装网上很多例子,以下是我主要参考的两篇博客: http://www.cnblogs.com/lidabo/p/3987378.html ...

  9. Mac开发者常用的工具

    http://www.oschina.net/news/53946/mac-dev-tools

  10. 【modelsim常见问题集锦】Can't launch the ModelSim-Altera software

    一.Can't launch the ModelSim-Altera software Error: Can't launch the ModelSim-Altera software -- the ...