转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove

题意:给出一个压缩后的串,以及一个模式串,问模式串出现了多少次。

http://acm.hdu.edu.cn/showproblem.php?pid=4668

这种压缩形式的话,在去年金华邀请赛中出现过,但是那题的范围不大。

直接展开作多串匹配,暴力AC自动机就行。

但是这题的原串不大,但是展开后会非常大。

可以发现压缩串把原串分为一个个区间,那么我们可以分两步统计。

预处理的话需要将压缩串解析成一个个的区间,在这里为了方便后面的匹配,我们假设模式串的长度为P

我在解析的时候,如果相邻两个区间的字符串长度都小于p的话,会将其合并,作用在后面说。

对于每一个区间,查询匹配次数。

1、如果这个区间非压缩的,直接KMP

2、如果这个区间是压缩后的,肯定不能展开暴力KMP。我们只需要统计匹配的起始位置在第一个循环节内的,因为我们在第一个循环节后面添加上p - 1个字符。这样保证了匹配位置在第一个循环节内,然后 便是统计。

这里有点麻烦的是,[ab]10中查询ab的话,我们应该 是aba中查询ab,发现出现了1次,那么最终结果应该统计为多少呢,按理说,aba这个串占用了两个循环节,那么总共有9个aba,应该 是9次,但是显然这里应该 是10次。那么对于[ab]10里面查询ba的话,同样还是把aba拿出来匹配,出现了1次,那么这里应该是9次。看似类似的情况,统计结果却不一样,因为第一次匹配只占用本身这个循环节,而第二次占用了所有循环节。

那么我们在后面添加 p - 1个字符之后,同样是处理kmp,同样是考虑匹配位置占用了所有的循环节统计,然后 再添加上不占用最后一个循环节次数。如[ab]10查询ab,aba中出现一次ab,而[ab]10中有9个aba,所以出现9次,然后再统计ab中有多少个ab,答案为1,所以最终为10。
 注意有些地方的表述,最好用一个较长的串再模拟一下,如[ab]10和[ba]10中查询abab这个串的情况。

第一个问题就算解决 了

第二个问题是跨区间的串,即模式串出现在两个或者两个以上的区间中。

既然如此,要保证这个匹配串要横跨到下一个区间,那么当前区间取一个长度为p - 1的后缀,那么匹配的话肯定会到下一个区间,下一个区间的话就取一个p - 1的前缀,那么保证匹配的串会出现在第一个区间中。

虽然我在前面解析的过程中,保证相邻两个区间长度小于p的话,会合并。

但是有一种情况是[ab]1000000cd[ab]10000000。那么对于中间的区间长度还是小于p。

所以就有可能匹配串横跨三个区间,这里需要特判一下,即第一个区间不超过p - 1,第二个区间全取,第三个区间加上第二个区间的长度要不超过p - 1。

总之就是这么麻烦。。。。应该是我实现得太麻烦。。。

不过唯一的好处便是范围不大,我是用String各种乱搞的。。。

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <map>
  5. #include <vector>
  6. #include <string>
  7. #include <queue>
  8. #include <cmath>
  9. #include <algorithm>
  10. #define lson step << 1
  11. #define rson step << 1 | 1
  12. #pragma comment(linker,"/STACK:102400000,102400000")
  13. using namespace std;
  14. typedef long long LL;
  15. const int N = 5005;
  16. struct Node {
  17. string s;
  18. int cnt;
  19. Node () {}
  20. Node (string _s , int c) :s(_s) , cnt(c) {}
  21. string cat () {
  22. string t = s;
  23. for (int i = 1 ; i < cnt ; i ++)
  24. s = s + t;
  25. cnt = 1;
  26. return s;
  27. }
  28. LL len () {
  29. return (LL)s.size() * cnt;
  30. }
  31. //
  32. string prefix (int l) {
  33. string str = s;
  34. for (int i = 1 ; i < cnt && str.size() < l ; i ++) {
  35. str += s;
  36. }
  37. return str.substr (0 , l);
  38. }
  39. string suffix (int l) {
  40. string str = s;
  41. for (int i = 1 ; i < cnt && str.size() < l ; i ++) {
  42. str += s;
  43. }
  44. return str.substr (str.size() - l , l);
  45. }
  46. }a[N];
  47. char str[N] , pat[N];
  48. int next[N] , idx , l , p;
  49. void get_next (char *s , int l) {
  50. next[0] = -1;
  51. int i = 0 , j = -1;
  52. while (i < l) {
  53. if (j == -1 || s[i] == s[j]) {
  54. i ++; j ++;
  55. next[i] = j;
  56. }
  57. else j = next[j];
  58. }
  59. }
  60. void gao (string s , int tot) {
  61. if (s == "") return ;
  62. if (idx == 0 || s.size() * tot >= p || a[idx - 1].len() >= p) {
  63. a[idx ++] = Node (s , tot);
  64. }
  65. else {
  66. a[idx - 1].cat ();
  67. a[idx - 1].s += Node (s , tot).cat();
  68. }
  69. }
  70. int match (string s , char *t , int p) {
  71. int l = s.size() ;
  72. int i = 0 , j = 0 , ans = 0;
  73. while (i < s.size()) {
  74. if (j == - 1 || s[i] == t[j]) {
  75. i ++; j ++;
  76. if (j == p) {
  77. ans ++;
  78. j = next[j];
  79. }
  80. }
  81. else j = next[j];
  82. }
  83. return ans;
  84. }
  85. int main () {
  86. #ifndef ONLINE_JUDGE
  87. freopen ("input.txt" , "r" , stdin);
  88. freopen ("output.txt" , "w" , stdout);
  89. #endif
  90. while (scanf ("%s %s" , str , pat) != EOF) {
  91. idx = 0;
  92. l = strlen (str);p = strlen (pat);
  93. get_next (pat , p);
  94. string s = "";
  95. int tot = 1;
  96. for (int i = 0 ; i < l ; i ++) {
  97. if (str[i] == '[') {
  98. if (s == "") continue;
  99. gao (s , tot);
  100. s = ""; tot = 1;
  101. }
  102. else if (str[i] == ']') {
  103. tot = 0;
  104. i ++;
  105. while (isdigit(str[i]))
  106. tot = tot * 10 + str[i ++] - '0';
  107. i --;
  108. gao (s , tot);
  109. s = ""; tot = 1;
  110. }
  111. else s += str[i];
  112. }
  113. gao (s , tot);
  114. s = ""; tot = 1;
  115. LL ans = 0;
  116. // for (int i = 0 ; i < idx ; i ++) {
  117. // cout << a[i].s << " " << a[i].cnt << endl;
  118. // }
  119. for (int i = 0 ; i < idx ; i ++) {
  120. if (a[i].len() < p) continue;
  121. if (a[i].cnt == 1) ans += match (a[i].s , pat , p);
  122. else {
  123. int use = min(a[i].cnt , 1 + (p - 1 + (int)a[i].s.size() - 1) / (int)a[i].s.size());
  124. string s = "";
  125. for (int j = 1 ; j < use ; j ++) {
  126. s += a[i].s;
  127. }
  128. s = a[i].s + s.substr (0 , min ((int)s.size() , p - 1));
  129. int tmp = match (s , pat , p);
  130. ans += (LL)tmp * (a[i].cnt - use + 1);
  131. if (p) {
  132. s = "";
  133. for (int j = 1 ; j < use ; j ++)
  134. s += a[i].s;
  135. ans += match (s , pat , p);
  136. }
  137. }
  138. }
  139. for (int i = 0 ; i < idx - 1 ; i ++) {
  140. s = a[i].suffix (min (a[i].len () , p - 1LL));
  141. if (a[i + 1].len () < p - 1) {
  142. s += a[i + 1].cat ();
  143. if (i + 2 < idx) {
  144. s += a[i + 2].prefix (min (a[i + 2].len () , p - 1 - a[i + 2].len ()));
  145. }
  146. }
  147. else {
  148. s += a[i + 1].prefix (min (a[i + 1].len () , p - 1LL));
  149. }
  150. ans += match (s , pat , p);
  151. }
  152. printf ("%I64d\n" , ans);
  153. }
  154. return 0;
  155. }

HDU 4668 Finding string (解析字符串 + KMP)的更多相关文章

  1. HDU 3374 String Problem (KMP+最大最小表示)

    HDU 3374 String Problem (KMP+最大最小表示) String Problem Time Limit: 2000/1000 MS (Java/Others)    Memory ...

  2. hdu 5510 Bazinga(字符串kmp)

    Bazinga Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Sub ...

  3. .NET面试题解析(03)-string与字符串操作

      系列文章目录地址: .NET面试题解析(00)-开篇来谈谈面试 & 系列文章索引 字符串可以说是C#开发中最常用的类型了,也是对系统性能影响很关键的类型,熟练掌握字符串的操作非常重要. 常 ...

  4. NVelocity解析字符串

    之前都是先从模板文件里面读取html字符串,现在要求将模板存入数据库或缓存了,怎么办呢?在网上找了下资料,终于找到解决办法. 如下: public class NVelocityHelper { // ...

  5. hdu1686字符串kmp

    The French author Georges Perec (1936–1982) once wrote a book, La disparition, without the letter 'e ...

  6. c# String.IndexOf 方法 string查找字符串

    c# String.IndexOf 方法 (value, [startIndex], [count]) 报告指定字符在此实例中的第一个匹配项的索引.搜索从指定字符位置开始,并检查指定数量的字符位置. ...

  7. java代码中fastjson生成字符串和解析字符串的方法和javascript文件中字符串和json数组之间的转换方法

    1.java代码中fastjson生成字符串和解析字符串的方法 List<TemplateFull> templateFulls = new ArrayList<TemplateFu ...

  8. JSON解析字符串

    JSON解析字符串 JSON 解析字符串时,应按严格的标准,否则无法解析: str1 = '{"str":"string","number" ...

  9. java解析字符串拆分单独元素

    有时候,需求要求传递多个字符串参数,但是方法参数已经固定为单个String,笔者在学习unity和android之间的消息传递时就遇到这个问题,所以就写了这么一个解析字符串拆分单独元素的方法. 示例: ...

随机推荐

  1. [置顶] 浏览器模式和标准对于javascript的影响

    今天在编写代码的时候遇到了一个莫名其妙的问题,请看下面 <html> <head> <title> Test </title> <!--<m ...

  2. Reverse Words in a String | LeetCode OJ | C++

    我的思路:先读取每一个单词,存放到容器中:读取完毕后,将容器中的单词倒序写入输出中. #include<iostream> #include<string> #include& ...

  3. Security:蠕虫的行为特征描述和工作原理分析

    ________________________ 参考: 百度文库---蠕虫的行为特征描述和工作原理分析 http://wenku.baidu.com/link?url=ygP1SaVE4t4-5fi ...

  4. Python 第七篇:异步IO\数据库\队列\缓存

    Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 RabbitMQ队列 Redis\Memcached缓存 Paramiko SSH Tws ...

  5. Android项目实战手机安全卫士(02)

    目录 项目结构图 源代码 运行结果 项目源代码 项目结构图 源代码 清单 01.  SplashActivity.java package com.coderdream.mobilesafe.acti ...

  6. mysql basic operation,mysql总结

    mysql> select * from wifi_data where dev_id like "0023-AABBCCCCBBAA" ; 1.显示数据库列表.show d ...

  7. 关于Linux系统清理/tmp/文件夹的原理

    转自:http://www.opsers.org/base/clean-up-on-the-linux-system-tmp-folder-you-may-want-to-know.html 我们知道 ...

  8. Atitit.Gui控件and面板----web server区----- web服务器监控面板and控制台条目

    Atitit.Gui控件and面板----web server区----- web服务器监控面板and控制台条目 1. Resin4.0.22 1 2. 查看http连接数::Summary>& ...

  9. 有关android工程的构建脚本(build.xml)的学习

    学习[android-sdk-linux根目录]/tools/ant/build.xml,觉得如下几点很有用,记录之 1)ant脚本中属性值是于前置定义优化的原则,即属性发生重复定义时,前面定义的值不 ...

  10. Excel 公式(细节若干)

    查找与引用: 1.如果需要找出匹配元素的位置而不是匹配元素本身,则应该使用 MATCH 函数而不是 LOOKUP 函数. 2.VLOOKUP的第一个参数允许使用通配符“*”来表示包含的意思,把*放在字 ...