HDU 4668 Finding string (解析字符串 + KMP)
转载请注明出处,谢谢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各种乱搞的。。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <string>
#include <queue>
#include <cmath>
#include <algorithm>
#define lson step << 1
#define rson step << 1 | 1
#pragma comment(linker,"/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
const int N = 5005;
struct Node {
string s;
int cnt;
Node () {}
Node (string _s , int c) :s(_s) , cnt(c) {}
string cat () {
string t = s;
for (int i = 1 ; i < cnt ; i ++)
s = s + t;
cnt = 1;
return s;
}
LL len () {
return (LL)s.size() * cnt;
}
//
string prefix (int l) {
string str = s;
for (int i = 1 ; i < cnt && str.size() < l ; i ++) {
str += s;
}
return str.substr (0 , l);
}
string suffix (int l) {
string str = s;
for (int i = 1 ; i < cnt && str.size() < l ; i ++) {
str += s;
}
return str.substr (str.size() - l , l);
}
}a[N];
char str[N] , pat[N];
int next[N] , idx , l , p;
void get_next (char *s , int l) {
next[0] = -1;
int i = 0 , j = -1;
while (i < l) {
if (j == -1 || s[i] == s[j]) {
i ++; j ++;
next[i] = j;
}
else j = next[j];
}
}
void gao (string s , int tot) {
if (s == "") return ;
if (idx == 0 || s.size() * tot >= p || a[idx - 1].len() >= p) {
a[idx ++] = Node (s , tot);
}
else {
a[idx - 1].cat ();
a[idx - 1].s += Node (s , tot).cat();
}
}
int match (string s , char *t , int p) {
int l = s.size() ;
int i = 0 , j = 0 , ans = 0;
while (i < s.size()) {
if (j == - 1 || s[i] == t[j]) {
i ++; j ++;
if (j == p) {
ans ++;
j = next[j];
}
}
else j = next[j];
}
return ans;
}
int main () {
#ifndef ONLINE_JUDGE
freopen ("input.txt" , "r" , stdin);
freopen ("output.txt" , "w" , stdout);
#endif
while (scanf ("%s %s" , str , pat) != EOF) {
idx = 0;
l = strlen (str);p = strlen (pat);
get_next (pat , p);
string s = "";
int tot = 1;
for (int i = 0 ; i < l ; i ++) {
if (str[i] == '[') {
if (s == "") continue;
gao (s , tot);
s = ""; tot = 1;
}
else if (str[i] == ']') {
tot = 0;
i ++;
while (isdigit(str[i]))
tot = tot * 10 + str[i ++] - '0';
i --;
gao (s , tot);
s = ""; tot = 1;
}
else s += str[i];
}
gao (s , tot);
s = ""; tot = 1;
LL ans = 0;
// for (int i = 0 ; i < idx ; i ++) {
// cout << a[i].s << " " << a[i].cnt << endl;
// }
for (int i = 0 ; i < idx ; i ++) {
if (a[i].len() < p) continue;
if (a[i].cnt == 1) ans += match (a[i].s , pat , p);
else {
int use = min(a[i].cnt , 1 + (p - 1 + (int)a[i].s.size() - 1) / (int)a[i].s.size());
string s = "";
for (int j = 1 ; j < use ; j ++) {
s += a[i].s;
}
s = a[i].s + s.substr (0 , min ((int)s.size() , p - 1));
int tmp = match (s , pat , p);
ans += (LL)tmp * (a[i].cnt - use + 1);
if (p) {
s = "";
for (int j = 1 ; j < use ; j ++)
s += a[i].s;
ans += match (s , pat , p);
}
}
}
for (int i = 0 ; i < idx - 1 ; i ++) {
s = a[i].suffix (min (a[i].len () , p - 1LL));
if (a[i + 1].len () < p - 1) {
s += a[i + 1].cat ();
if (i + 2 < idx) {
s += a[i + 2].prefix (min (a[i + 2].len () , p - 1 - a[i + 2].len ()));
}
}
else {
s += a[i + 1].prefix (min (a[i + 1].len () , p - 1LL));
}
ans += match (s , pat , p);
}
printf ("%I64d\n" , ans);
}
return 0;
}
HDU 4668 Finding string (解析字符串 + KMP)的更多相关文章
- HDU 3374 String Problem (KMP+最大最小表示)
HDU 3374 String Problem (KMP+最大最小表示) String Problem Time Limit: 2000/1000 MS (Java/Others) Memory ...
- hdu 5510 Bazinga(字符串kmp)
Bazinga Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Sub ...
- .NET面试题解析(03)-string与字符串操作
系列文章目录地址: .NET面试题解析(00)-开篇来谈谈面试 & 系列文章索引 字符串可以说是C#开发中最常用的类型了,也是对系统性能影响很关键的类型,熟练掌握字符串的操作非常重要. 常 ...
- NVelocity解析字符串
之前都是先从模板文件里面读取html字符串,现在要求将模板存入数据库或缓存了,怎么办呢?在网上找了下资料,终于找到解决办法. 如下: public class NVelocityHelper { // ...
- hdu1686字符串kmp
The French author Georges Perec (1936–1982) once wrote a book, La disparition, without the letter 'e ...
- c# String.IndexOf 方法 string查找字符串
c# String.IndexOf 方法 (value, [startIndex], [count]) 报告指定字符在此实例中的第一个匹配项的索引.搜索从指定字符位置开始,并检查指定数量的字符位置. ...
- java代码中fastjson生成字符串和解析字符串的方法和javascript文件中字符串和json数组之间的转换方法
1.java代码中fastjson生成字符串和解析字符串的方法 List<TemplateFull> templateFulls = new ArrayList<TemplateFu ...
- JSON解析字符串
JSON解析字符串 JSON 解析字符串时,应按严格的标准,否则无法解析: str1 = '{"str":"string","number" ...
- java解析字符串拆分单独元素
有时候,需求要求传递多个字符串参数,但是方法参数已经固定为单个String,笔者在学习unity和android之间的消息传递时就遇到这个问题,所以就写了这么一个解析字符串拆分单独元素的方法. 示例: ...
随机推荐
- Firemonkey使用iOS的第三方静态库(Link Binary With Libraries)
最近需要从内存流中直接播放音频,想到了使用第三方音频播放库bass.在windows上可以很方便的使用相应动态库(具体参考万一的博客),但在iOS上却没有相应的使用介绍,准确的说是没有用于Firemo ...
- Main方法的执行过程(转)
要运行一个 main 方法 , 首先要知道 main 方法所在的 Class, 在命令行中指定这个 Class 名 Class Lava{ Private int speed = 4; Void fl ...
- VC++在对话框中加入属性页
当一个基于对话框的程序中有相当多的控件时,你一定会想到使用属性页来将这些控件分类放置.本文针对这种方法来讨论几种可能实现的方案. 方案一本方案的例子请见源代码打包文件中的Property1部分 在对话 ...
- ICE之C/S通信原理
/* 在ICE文档中只需要声明module名称,接口名称,方法名称 */ #ifndef SIMPLE_ICE #define SIMPLE_ICE module Demo{ //module名称 i ...
- 原生app与web app的比较
http://www.2ee9.com/news/news_show_36_237.html http://zhidao.baidu.com/link?url=7lWq2tgqiMiDmsRd54hO ...
- TF-IDF与余弦相似性的应用(一):自动提取关键词 - 阮一峰的网络日志
TF-IDF与余弦相似性的应用(一):自动提取关键词 - 阮一峰的网络日志 TF-IDF与余弦相似性的应用(一):自动提取关键词 作者: 阮一峰 日期: 2013年3月15日 ...
- cocos2d-x on wp8架构简单介绍
1,基于C++的开发架构 支持3大移动平台以及3大桌面平台. 分为图形,声音,物理3大模块,另外还有脚本的导出. 在wp8/win32上的图形是基于d3d的,而在其它平台是基于opengl/openg ...
- 【iOS开发-72】设置状态栏的两种方式、程序生命周期以及更好地理解几大类(对象)之间的关系
(1)设置状态栏的2种方式 --第一种方式就是我们在控制器中设置,系统默认就是交给视图控制器去管理的,这样不同视图控制器能够自己定义不同的状态栏例如以下: -(BOOL)prefersStatusBa ...
- javascript操作元素的css样式
我们经常要使用Javascript来改变页面元素的样式.当中一种办法是改变页面元素的CSS类(Class),这在传统的Javascript里,我们一般是通过处理HTML Dom的classname特性 ...
- 面试中关于Java中涉及到知识点(转)
本篇文章会对面试中常遇到的Java技术点进行全面深入的总结,帮助我们在面试中更加得心应手,不参加面试的同学也能够借此机会梳理一下自己的知识体系,进行查漏补缺. 1. Java中的原始数据类型都有哪些, ...